【问题标题】:Passing template function as argument for normal function将模板函数作为普通函数的参数传递
【发布时间】:2015-08-31 12:58:12
【问题描述】:

我想知道是否可以将模板函数(或其他)作为参数传递给第二个函数(不是模板)。 向 Google 询问这件事似乎只会提供相反的信息 (Function passed as template argument)

我能找到的唯一相关页面是http://www.beta.microsoft.com/VisualStudio/feedbackdetail/view/947754/compiler-error-on-passing-template-function-as-an-argument-to-a-function-with-ellipsis (不是很有帮助)

我期待这样的事情:

template<class N>void print(A input){cout << input;}
void execute(int input, template<class N>void func(N)){func(input)}

然后再调用

execute(1,print);

那么,可以这样做还是必须为 execute() 定义另一个模板?

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    函数模板代表一个无限的重载集,所以除非你有一个与特化兼容的目标类型,否则函数类型的推导总是失败的。例如:

    template<class T> void f(T);
    template<class T> void h(T);
    
    void g() {
        h(f); // error: couldn't infer template argument 'T'
        h(f<int>); // OK, type is void (*)(int)
        h<void(int)>(f); // OK, compatible specialization
    }
    

    从上面我们可以看出,程序的有效性要求我们为函数模板指定模板参数,而通常指定它们并不总是直观的。您可以改为使 print 成为具有通用重载调用运算符的函子作为额外的间接级别:

    struct print {
         template<typename T>
         void operator()(T&& x) const {
             std::cout << x;
         }
    };
    

    现在您可以让 execute 接受任何 Callable 并使用输入调用它:

    template<class T, class Op>
    void execute(T&& input, Op&& op) {
        std::forward<Op>(op)(std::forward<T>(input));
    }
    
    void g() { execute(1, print{}); }
    

    通用 lambdas (C++14) 使这更加简洁:

    execute(1, [] (auto&& x) { std::cout << x; });
    

    【讨论】:

    • sweet,最后一个示例是可编译的,而不是 void print(auto x){std::cout
    • @LukeNaylor auto 不允许在函数参数中,仅在 lambda 声明中。即使是这样,它也会与您在原始示例中的模板版本相同。 lamda 工作的原因是因为它创建了一个仿函数,就像我在第二个代码补丁中向您展示的那样。
    • 备注:在这种情况下execute 不是一个“普通”函数,它是一个函数模板。然而,将 Op 更改为 std::function&lt;...&gt; 将使其成为正常功能(以运行时开销为代价)。
    【解决方案2】:

    Execute 需要是一个模板——编译器无法创建适用于任何输入类型的单一版本的执行。现在,如果你为这个特定的函数指定 N 是什么——例如,如果你制作了第二个参数 print——那么它应该是合法的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-14
      • 2010-11-13
      • 2011-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-28
      相关资源
      最近更新 更多