問題描述
使用 std::function
,我們可以使用 argument_type
、second_argument_type
等 typedef 來獲取參數的類型,但我可以看不到用 lambda 做同樣事情的方法.是否可以?(我使用的是 VS2010)
Using std::function
, we can get the type of an argument using the argument_type
, second_argument_type
etc. typedefs, but I can't see a way to do the same thing with lambdas. Is it possible? (I'm using VS2010)
假設我想要在用于讀取對象并將其傳遞給 setter 函數的反序列化系統中使用以下內容:
Say I want something like the following in my deserialization system used to read an object and pass it to a setter function:
template<typename F>
static void forward(F f)
{
// Create an object of the type of the first
// parameter to the function object F
typedef typename F::argument_type T;
T t;
//...do something with 't' here (deserialize in my case)
// Forward the object to the function
f(t);
}
它可以像這樣使用并且一切正常:
It can be used like this and everything works fine:
std::function<void(int)> f = [](int i) -> void { setValue(i); };
forward(f);
但它不能直接與 lambdas 一起使用:
But it will not work directly with lambdas:
forward([](int i) -> void { setValue(i); });
//error C2039: 'argument_type' : is not a
//member of '`anonymous-namespace'::<lambda1>'
有沒有一種方法可以以同時適用于 lambda 和 std::function
對象的方式訪問參數類型?也許是一種先獲取 lambda 的 std::function
類型,然后從中獲取 argument_type
的方法?
Is there a way to access the parameter types in a way that will work for both lambdas and std::function
objects? Maybe a way to get the std::function
type of a lambda first, and then the argument_type
from that?
根據下面的答案,適用于 lambdas 和 std::function
的版本是:
Following on from the answer below, a version that works with lambdas and std::function
is:
template<typename T, typename F>
static void forward(F f)
{
T t;
//...do something with 't' here (deserialize in my case)
f(t);
}
forward<int>([](int i) -> void { setValue(i); });
由于 int
在這里重復,我希望擺脫它 - 對于 int
來說還不錯,但對于幾個命名空間中的長命名類型來說更煩人.C'est la vie!
Since int
is repeated here I was hoping to get rid of it - not so bad for int
but more annoying for long-named types in a couple of namespaces. C'est la vie!
推薦答案
在一般情況下是不可取的.(請注意,std::function
很容易指定例如 argument_type
是什么:它只是 A
!它在類型定義中可用.)
It's not desirable in the general case. (Note that it's quite easy for std::function<T(A)>
to specify what e.g. argument_type
is: it's just A
! It's available in the type definition.)
可以要求每個函數對象類型指定其參數類型,然后強制要求從 lambda 表達式生成的閉包類型這樣做.事實上,像自適應函子這樣的 C++0x 之前的特性只適用于這種類型.
It would be possible to require each and every function object type to specify its argument types, and in turn mandate that the closure types generated from lambda expression do so. In fact, pre-C++0x features like adaptable functors would only work for such types.
然而,我們正在使用 C++0x 并且有充分的理由.最簡單的就是簡單的重載:一個帶有模板化 operator()
的函子類型(又名多態函子)簡單地接受所有類型的參數;那么 argument_type
應該是什么?另一個原因是泛型代碼(通常)試圖對其操作的類型和對象指定最少的約束,以便更容易(重新)使用.
However, we're moving from that with C++0x and for good reasons. The simplest of which is simply overloading: a functor type with a templated operator()
(a.k.a a polymorphic functor) simply takes all kind of arguments; so what should argument_type
be? Another reason is that generic code (usually) attempts to specify the least constraints on the types and objects it operates on in order to more easily be (re)used.
換句話說,對于給定的 Functor f
, typename Functor::argument
是 int代碼>.知道
f(0)
是一個可接受的表達式,更有趣.為此,C++0x 提供了諸如 decltype
和 std::declval
之類的工具(方便地將兩者打包在 std::result_of
中).
In other words, generic code is not really interested that given Functor f
, typename Functor::argument
be int
. It's much more interesting to know that f(0)
is an acceptable expression. For this C++0x gives tools such as decltype
and std::declval
(conveniently packaging the two inside std::result_of
).
在我看來,您有兩種選擇:要求傳遞給模板的所有函子使用 C++03 風格的約定,指定 argument_type
等;使用以下技術;或重新設計.我建議使用最后一個選項,但這是您的決定,因為我不知道您的代碼庫是什么樣的或您的要求是什么.
The way I see it you have two choices: require that all functors passed to your template use a C++03-style convention of specifying an argument_type
and the like; use the technique below; or redesign. I'd recommend the last option but it's your call since I don't know what your codebase looks like or what your requirements are.
對于單態函子類型(即沒有重載),可以檢查 operator()
成員.這適用于 lambda 表達式的閉包類型.
For a monomorphic functor type (i.e. no overloading), it is possible to inspect the operator()
member. This works for the closure types of lambda expressions.
所以我們聲明這些助手
template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...));
template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...) const);
// volatile or lvalue/rvalue *this not required for lambdas (phew)
接受一個指向至少一個參數的成員函數的指針.現在:
that accept a pointer to member function taking at least one argument. And now:
template<typename F>
struct first_argument {
typedef decltype( helper(&F::operator()) ) type;
};
[一個精心設計的特征可以連續查詢左值-右值/常量/易失性重載,如果第一個參數對所有重載都相同,則公開第一個參數,或者使用 std::common_type
.]
[ an elaborate trait could successively query the lvalue-rvalue/const/volatile overloads and expose the first argument if it's the same for all overloads, or use std::common_type
.]
這篇關于我們可以獲得 lambda 參數的類型嗎?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!