Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 接受任何类型的可调用,也知道参数类型_C++_Templates_C++11_Lambda_Functor - Fatal编程技术网

C++ 接受任何类型的可调用,也知道参数类型

C++ 接受任何类型的可调用,也知道参数类型,c++,templates,c++11,lambda,functor,C++,Templates,C++11,Lambda,Functor,我不确定这是否可能,所以这就是我想知道的 我想创建一个接受任何类型的functor/可调用对象的函数,但我想知道参数类型是什么。(但不强制执行) 所以,这一个包含了所有内容,但没有给出参数的类型: template < typename T > void optionA( T ); 不会编译。 这有点奇怪,因为这将编译: std::function< void(int) > func = [](int){}; optionB( func ); std::functio

我不确定这是否可能,所以这就是我想知道的

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

所以,这一个包含了所有内容,但没有给出参数的类型:

template < typename T >
void optionA( T );
不会编译。 这有点奇怪,因为这将编译:

std::function< void(int) > func = [](int){};
optionB( func );
std::functionfunc=[](int){};
选择权B(职能);
那么,有没有一种方法可以接受所有选项,并知道需要哪种类型的参数呢

提前谢谢

--编辑--

我之所以要这样做,是因为我希望库的用户注册一个具有特定类型的回调。对我来说,最自然的方式是

auto callback = []( int val ) { cout << "my callback " << val << endl; };
object.register( callback );
autocallback=[](int-val){cout
template
无效选项(函数<无效(T)>)
{
cout(func));
}
模板
无效包装(F&F,无效(F::*函数)(A)常数)
{
选项(函数(绑定(函数,f,占位符::_1));
}
模板
空白包装纸(F&F,空白(F::*func)(A))
{
选项(函数(绑定(函数,f,占位符::_1));
}
模板
无效期权(T)
{
包装器(t,&t::operator());
}
无效测试(int)
{
}
结构对象
{
void操作符()(浮点)
{
}
};
int main(int,char*[])
{
对象对象对象;
选项(测试);
选项([](双){});
期权(obj);
返回0;
}
基于这里的信息,我通过@dyps链接找到了这些信息

这不是最好的解决方案,因为它需要常量/非常量/volatile等的重载。
就我试图解决的原始问题而言,它确实完成了工作…

这里的示例适用于大多数可调用函数,包括functor和lambda(尽管不适用于@Yakk在对问题的评论中所演示的泛型functor)

该代码在确定返回类型和多个参数时也很有用

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;
}
模板
结构函数特性:公共函数特性{};
模板
结构函数特性{
使用结果类型=Ret;
模板
结构参数{

使用type=typename std::tuple_元素“但此元素不允许lambdas”它确实允许lambda,但它不能推导出
T
。因此,如果您明确指定
T
,它应该可以工作。它也不适用于函数名和函数指针。您可以尝试编写一些重载:对于函数指针,
std::function
s,以及只接受
T
(对于lambda/函数对象)。但是,最后一个不允许您推断参数类型(例如,通用lambda),但您可以尝试在
t
中找到
运算符()
,并推断其参数类型(仅当只有一个参数类型时才可能)@dyp,这很公平,但我觉得这不够好,因为这迫使我“两次”指定参数,一次在选项调用中,一次在lamba中。我打算在库中使用它,我知道如果它不“正常工作”,我会感到困惑。那么我们能做得更好吗?如何推断函数对象的参数类型的增强版(使用单个
运算符()
)。
结构问题{templatevoid运算符()(T&&T)常量{std::coutI认为可以通过
std::is_member_function_pointer
和泛型分解特性实现成员函数重载。lambda btw为函数指针选择第二个重载,因为它可以转换为函数指针,但只有在它是无状态的情况下。我建议添加一个只需要a
T
然后尝试检测
运算符()
.o那太糟糕了:你会得到cv限定符和ref限定符的组合。幸运的是,你只需要做一次:我接受这个答案,即使它有相同的常量/可变/可变修饰符问题。由于这个方法提供了一种检测参数类型的通用方法,因此它更有用。你有什么理由这样做吗你是对的,它应该是
t
而不是
decltype(t)
std::decay
仍然是需要的,尽管在进行类型推断时,特殊规则适用于
t&
(通用参考)。在标准中使用此
函数\u traits
模板将非常有用。此外,将任何可调用函数转换为函数的
make\u函数将非常有用。
auto callback = []( int val ) { cout << "my callback " << val << endl; };
object.register( callback );
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;
}
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...)> { /* ... */ }