假设你有一个仿函数:
struct MyFunctor
{
bool operator ()( int value )
{
return true;
}
};
是否可以检索仿函数成员的参数类型以便在模板中使用?以下是这种神话功能的用法:
template < typename FunctorType >
bool doIt( FunctorType functor, typename FunctorType::operator()::arg1 arg )
{
return functor( arg );
}
是否有一种有效的语法可以替代我神秘的FunctorType::operator()::arg1
?
答案 0 :(得分:6)
如果您知道该项目是仿函数,那么您可以抓住它的operator()
,如下所示:
#include <iostream>
template <unsigned Idx, typename... T>
struct pick
{
static_assert(Idx < sizeof...(T), "cannot index past end of list");
};
template <typename T, typename... TRest>
struct pick<0U, T, TRest...>
{
typedef T result;
};
template <unsigned Idx, typename T, typename... TRest>
struct pick<Idx, T, TRest...>
{
typedef typename pick<Idx-1, TRest...>::result result;
};
template <typename Func>
struct func_traits;
template <typename TObj, typename R, typename... TArgs>
struct func_traits<R (TObj::*)(TArgs...)>
{
typedef R result_type;
template <unsigned Idx>
struct argument
{
typedef typename pick<Idx, TArgs...>::result type;
};
};
template <typename Func,
typename Traits = func_traits<Func>,
typename R = typename Traits::result_type,
typename Arg0 = typename Traits::template argument<0>::type,
typename Arg1 = typename Traits::template argument<1>::type
>
void foo(Func f)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
};
struct thing
{
void operator()(long, int*) { }
};
int main()
{
foo(&thing::operator());
}
对我来说,该节目打印出来:
void foo(Func) [with Func = void (thing::*)(long int, int*), Traits = func_traits<void (thing::*)(long int, int*)>, R = void, Arg0 = long int, Arg1 = int*]
关键点是Arg0
和Arg1
分别是long
和int*
。
答案 1 :(得分:4)
不,没有。最优雅的方法是要么你的函子要为参数类型提供typedef
,要么引入特征类。如果您希望模板与仿函数和函数一起使用,后者非常有用。
或者,您可以将参数类型设为第二个模板参数:
template < typename FunctorType, class ArgumentType >
bool doIt( FunctorType functor, ArgumentType arg )
{
return functor( arg );
}
如果ArgumentType
与仿函数所需的类型不匹配,编译器仍会抱怨。
答案 2 :(得分:3)
你可以用C ++ 0x
来做template <typename... Args>
struct Function {
typedef std :: tuple <Args...> args;
void call () (Args... args);
}
template <typename... Args>
void do_it (Function<Args...>::args:: SOMETHING :: type t, Args... args) {
something (t)
Function <Args...> :: call (args...);
}
答案 3 :(得分:2)
这里我给@BjörnPollex(正确)答案提供了C ++ 11更新。
回到这个问题,你想明确地指定doIt
的第二个参数主要是为了限制可以传递的内容。在C ++ 11中,你可以暗示这个限制,而无需明确知道仿函数的参数类型(如果算函数重载,则没有明确定义)。
template < typename FunctorType, class ArgumentType >
auto doIt( FunctorType functor, ArgumentType arg ) -> decltype(bool(functor(arg)))
{
return functor( arg );
}
(转换为bool
可能不是必需的,我把它放在这里,因为看起来你真的希望返回类型为bool
)。
此doIt
(模板)函数将接受任何可能与functor
参数兼容的参数(并且也可转换为bool
)。如果传递的参数不兼容,则该函数根本不存在,并且将产生优雅的“doIt function not found”编译器错误。
通过使用完美转发使doIt
完全等同于functor(arg)
,可以更进一步:
template < typename F, class A >
auto doIt( F&& f, A&& a ) -> decltype(bool(std::forward<F>(f)(std::forward<A>(a))))
{
return std::forward<F>(f)( std::forward<A>(a) );
}