C++ 可变高阶函数的过载分解

C++ 可变高阶函数的过载分解,c++,templates,c++11,variadic-templates,C++,Templates,C++11,Variadic Templates,假设我有一个可变的高阶函数 template<typename F, typename ...Args> void execution(F func, Args&&... args) { func(std::forward<Args>(args)...); } 过载解决方案将是 然而,如果只提供其中一个,程序 为什么会发生这种情况?模板参数推断失败的原因 如果我从集合中删除f(),并将其替换为f(arg,arg2)仍然存在一个错误。是否有变通方法

假设我有一个可变的高阶函数

template<typename F, typename ...Args>
void execution(F func, Args&&... args)
{
    func(std::forward<Args>(args)...);
}
过载解决方案将是

然而,如果只提供其中一个,程序

  • 为什么会发生这种情况?模板参数推断失败的原因
  • 如果我从集合中删除
    f()
    ,并将其替换为
    f(arg,arg2)
    仍然存在一个错误。是否有变通方法,或者我是否总是必须将函数的属性作为模板参数

    execution<void()>(f);
    
    执行(f);
    

  • 没有可用的特定功能“f”:

    简化它:

    template<typename F>
    void execution(F func)
    {}
    
    void f() {}
    void f(int arg) {}
    
    int main()
    {
        execution(f);
        return 0;
    }
    
    模板
    无效执行(F func)
    {}
    void f(){}
    void f(int arg){}
    int main()
    {
    执行(f);
    返回0;
    }
    

    有两个函数“f”可用于模板参数推断/替换

    在进行模板类型推断时,编译器不会分析函数中如何使用类型。因此,在推导模板参数时,编译器看不到不同模板参数之间的关系。因此,额外的可变模板参数根本不重要,问题可以简化为

    template<typename Func> void execution(Func func);
    
    void f();
    void f(int);
    
    execution(f);
    
    模板作废执行(Func Func);
    无效f();
    无效f(int);
    执行(f);
    
    有了这段最小化的代码,模板参数推断失败的原因就显而易见了

    您可以通过使第一个参数显式依赖于其余模板参数来解决此问题,例如:

    template<typename... Args>
     void execution(void (*func)(Args ...), Args ... args)
    {
      func(std::forward<Args>(args) ...);
    }
    
    模板
    作废执行(作废(*func)(参数…,参数…)
    {
    func(std::forward(args)…);
    }
    
    您需要一个重载集对象。这是一个表示
    f
    的整个重载函数集的对象:

    struct f_overload_set {
      template<typename...As>
      auto operator()(As&&...as)->
        decltype(f(std::declval<As>()...))
      { return f(std::forward<As>(as)...); }
    };
    
    struct f_重载集{
    模板
    自动运算符()(As&&…As)->
    decltype(f(std::declval()…)
    {返回f(std::forward(as)…);}
    };
    
    现在将
    f_重载{}
    传递给
    模板
    函数


    <代码>模板<代码>函数值参数必须是值,而在当前C++中没有表示函数的整个重载集的第一类值。符号

    f
    在每个使用点被消歧为一个重载:但这需要在使用点有一个直接的上下文。上面的问题是在我们有参数的前提下进行消歧。

    是否存在C++乔恩SKET?这首先是模板参数推导的问题,较少的过载分辨率。C++1y解决方案是编写
    执行([](auto&&…pp){returnf(std::forward(pp);})。这是一个已知的问题,我猜这个问题有多个重复项。
    std::function
    不需要拒绝无法为模板参数中提供的参数类型调用的函数。这是一个QoI问题。此外,您的解决方案需要在调用站点将
    f
    显式转换为
    std::function
    类型:只有在给定显式目标类型(例如
    void execution(void(*)(int));
    )时,不同函数之间才会发生重载解析。
    std::function
    类型只有构造函数模板,因此不会发生重载解析,并且
    f
    将是不明确的。@dyp:谢谢,我没有注意到
    std::function
    的问题。我已经将代码更改为一个简单的函数指针;虽然灵活性较差,但它应该解决手头的问题。
    voidfoo(int);模板作废执行(作废(*func)(参数…,参数…);int main(){execution(foo,3.0);}
    做什么?Ie,此修复程序不足。@Yakk:它给出了一个错误,因为没有
    f(double)
    。我会考虑预期的行为。你期待什么样的行为?这就解决了问题。我想我已经算出了C++14:
    #define LIFT(f)[](auto&&…a)->decltype(auto){return f(std::forward(a)…);}
    。如果您不想依赖于
    ,请将
    std::forward
    替换为
    static\u cast
    template<typename... Args>
     void execution(void (*func)(Args ...), Args ... args)
    {
      func(std::forward<Args>(args) ...);
    }
    
    struct f_overload_set {
      template<typename...As>
      auto operator()(As&&...as)->
        decltype(f(std::declval<As>()...))
      { return f(std::forward<As>(as)...); }
    };