将模板函数作为参数传递给普通函数

10

我想知道是否可以将模板函数(或其他函数)作为参数传递给不是模板的第二个函数。

在Google上搜索只能得到有关相反情况的信息(将函数作为模板参数传递

我找到的唯一相关页面是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()定义另一个模板?

2个回答

14

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

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接受任何可调用对象,并使用输入值调用它:
template<class T, class Op>
void execute(T&& input, Op&& op) {
    std::forward<Op>(op)(std::forward<T>(input));
}

void g() { execute(1, print{}); }

C++14引入了泛型lambda表达式,使得代码更加简洁:

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

甜的,最后一个示例能编译而 void print(auto x){std::cout<<x;}execute(1,print); 不能编译,有什么原因吗?无名函数被完全不同地处理吗? - Luke Naylor
@LukeNaylor 在函数参数中不允许使用 auto,只能在 lambda 声明中使用。即使可以,它也与您原始示例中的模板版本相同。Lambda 能够工作的原因是它创建了一个类似于我在第二个代码补丁中向您展示的那样的函数对象。 - David G
请注意:在这种情况下,“execute”不是一个“普通”的函数,而是一个函数模板。但是,将“Op”更改为“std::function<...>”将使其成为普通函数(以运行时开销为代价)。 - user202729

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接