接受任何类型的可调用并且也知道参数类型

Arj*_*jan 14 c++ lambda templates functor c++11

我不确定是否可能,所以这就是我想要找到的.

我想创建一个接受任何类型的函子/可调用对象的函数,但我想知道参数类型是什么.(但不强制执行)

所以,这个捕获所有但不给我参数的类型:

template < typename T >
void optionA( T );
Run Code Online (Sandbox Code Playgroud)

这个捕获最多,并具有参数的类型

template < typename T >
void optionB( std::function< void(T) > );
Run Code Online (Sandbox Code Playgroud)

但是这个不允许lambdas,所以

optionB( [](int){} );
Run Code Online (Sandbox Code Playgroud)

不会编译.这有点奇怪,因为这将编译:

std::function< void(int) > func = [](int){};
optionB( func );
Run Code Online (Sandbox Code Playgroud)

那么有没有办法接受所有选项,还知道期望哪种类型的参数?

提前致谢!

- 编辑 -

我想这样做的原因是我想让我的库用户注册一个特定类型的回调.对我来说,最自然的方式是

auto callback = []( int val ) { cout << "my callback " << val << endl; };
object.register( callback );
Run Code Online (Sandbox Code Playgroud)

(使用或不使用回调作为中间变量)

由于我需要根据用户期望的值类型修改行为,我需要知道他/她期望的类型.

Snp*_*nps 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;
}
Run Code Online (Sandbox Code Playgroud)

要添加对常规函数的支持,请添加专门化,例如

template <typename Ret, typename... Args>
struct func_traits<Ret(*)(Args...)> { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

更有用的信息: 是否可以找出lambda的参数类型和返回类型?


Arj*_*jan 5

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;
}
Run Code Online (Sandbox Code Playgroud)

基于此处找到的信息c++0x: lambda arity 上的重载,这是我通过 @dyps 链接找到的

这不是最好的解决方案,因为它需要常量/非常量/易失性等的重载。它确实根据我试图解决的原始问题完成了工作......