我不确定这是否可能,所以这就是我想要找到的。
我想创建一个接受任何类型的functor / callable对象的函数,但我想知道参数类型是什么。 (但不强制执行)
所以,这个捕获所有但不给我参数的类型:
template < typename T >
void optionA( T );
这个捕获最多,并且具有参数类型
template < typename T >
void optionB( std::function< void(T) > );
但是这个不允许lambdas,所以
optionB( [](int){} );
不会编译。 这有点奇怪,因为这会编译:
std::function< void(int) > func = [](int){};
optionB( func );
那么有没有办法接受所有选项,还知道期望哪种类型的参数?
提前感谢!
- 编辑 -
我之所以这样做,是因为我希望我的库用户注册一个特定类型的回调。对我而言,最自然的方式是
auto callback = []( int val ) { cout << "my callback " << val << endl; };
object.register( callback );
(使用或不使用回调作为中间变量)
由于我需要根据用户期望的值类型修改行为,我需要知道他/她期望的类型。
答案 0 :(得分:7)
这是一个适用于大多数可调用函数的示例,包括仿函数和lambda(尽管不是泛型仿函数,因为@Yakk在对该问题的评论中进行了演示)。
在确定返回类型和多个参数时,代码也很有用。
template <typename T>
struct func_traits : public func_traits<decltype(&T::operator())> {};
template <typename C, typename Ret, typename... Args>
struct func_traits<Ret(C::*)(Args...) const> {
using result_type = Ret;
template <std::size_t i>
struct arg {
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
template <typename T>
void option(T&& t) {
using traits = func_traits<typename std::decay<T>::type>;
using return_t = typename traits::result_type; // Return type.
using arg0_t = typename traits::template arg<0>::type; // First arg type.
// Output types.
std::cout << "Return type: " << typeid(return_t).name() << std::endl;
std::cout << "Argument type: " << typeid(arg0_t).name() << std::endl;
}
要添加对常规函数的支持,请添加特殊化,例如
template <typename Ret, typename... Args>
struct func_traits<Ret(*)(Args...)> { /* ... */ }
更有用的信息: Is it possible to figure out the parameter type and return type of a lambda?
答案 1 :(得分:4)
template < typename T >
void option( function< void(T) > )
{
cout << typeid( T ).name() << endl;
}
template < typename T >
void option( void (*func)(T) )
{
option( function< void(T) >( func ) );
}
template< typename F, typename A >
void wrapper( F &f, void ( F::*func )( A ) const )
{
option( function< void(A) >( bind( func, f, placeholders::_1 ) ) );
}
template< typename F, typename A >
void wrapper( F &f, void ( F::*func )( A ) )
{
option( function< void(A) >( bind( func, f, placeholders::_1 ) ) );
}
template < typename T >
void option( T t )
{
wrapper( t, &T::operator() );
}
void test( int )
{
}
struct Object
{
void operator ()( float )
{
}
};
int main( int, char *[] )
{
Object obj;
option( test );
option( [](double){} );
option( obj );
return 0;
}
根据c++0x: overloading on lambda arity中的信息,我通过@dyps链接找到了
这不是最好的解决方案,因为它需要const / non-const / volatile等的重载。 它确实按照我试图解决的原始问题完成了工作......