【问题标题】:non-capturing lambda and function pointer as parameter in overloaded function ambiguity非捕获 lambda 和函数指针作为重载函数歧义中的参数
【发布时间】:2019-11-22 06:36:27
【问题描述】:
#include <functional>
#include <iostream>

template<typename T>
void test( std::function< void ( const T& ) > f )
{
    T val {};
    f( val );

    std::cout << "std::function" << std::endl;
}

template<typename T>
void test( void(*f) ( const T& ) )
{
    T val {};
    f( val );

    std::cout << "function pointer" << std::endl;
}

int main()
{
    auto capturing_var { 0 };

    // Works because implicit conversion to function pointer isn't applied when lambda is capturing
    test< int >( [ capturing_var ]( const int& x ) { } );

    // Doesn't work because implicitly convertible to function pointer and makes ambiguity
    // I want this line to work somehow, how can i make it worked with same client code ? Is it possible ?
    test< int >( []( const int& x ) { } );

    // This line is finer if it works, but in this case compiler cannot deduce T and also ambiguous if it could
    test( []( const int& x ) { } );

    // Works because of unary + operator so conversion to function ptr and i dont need to specify T
    test( +[]( const int& x ) { } );

    return 0;
}

实际上我只是希望这段代码能够在不更改main() 中的任何内容的情况下工作,但我不确定这是否可能。

我可以省略采用函数指针的重载函数,然后它会起作用,但在这种情况下,我需要指定 T 是什么。

注意:我需要推导出T

【问题讨论】:

    标签: c++ function-pointers std-function overload-resolution


    【解决方案1】:

    您可以使用this question 中描述的技术和一些小的后处理。

    小例子:

    template<typename Ret, typename Arg>
    Arg argument_type(Ret(*)(Arg));
    
    template<typename Ret, typename Fn, typename Arg>
    Arg argument_type(Ret(Fn::*)(Arg) const);
    
    template<typename Fn>
    auto argument_type(Fn) -> decltype(argument_type(&Fn::operator()));
    
    template<typename Arg, typename Fn>
    struct argument {
        static_assert(std::is_invocable_v<Fn, Arg>);
        using type = Arg;
    };
    
    template<typename Fn>
    struct argument<void, Fn>{
        using type = decltype(argument_type(std::declval<Fn>()));
    };
    
    template<typename T = void, typename Fn>
    void test(Fn fn) {
        using Arg = std::decay_t<typename argument<T, Fn>::type>;
        std::cout << "Arg = " << boost::typeindex::type_id_with_cvr<Arg>().pretty_name() 
                  << std::endl;
    }
    
    int main() {
        int capturing_var;
    
        test<int>([capturing_var](const int& x) {}); // Arg = int
        test<int>([](const int& x) {});              // Arg = int
        test([](const int& x) {});                   // Arg = int 
        test(+[](const int& x) {});                  // Arg = int
        test<int>([](auto x) {});                    // Arg = int
    }
    

    如果无法推断出参数类型,例如,对于可变参数 lambda,则必须提供它(最后一个示例)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-19
      • 2013-07-26
      • 2016-11-12
      • 2016-09-19
      • 1970-01-01
      • 1970-01-01
      • 2014-07-16
      相关资源
      最近更新 更多