编辑:一个单线摘要:是否可以创建一个模板化类型,其operator()调用任意函数,指定为模板参数?
考虑(模板化)函数
template <typename T> std::operator-(const T& lhs, const T& rhs)
在标准C ++库中,<functional>
我们have以下构造(忽略constexpr和C ++ 14中的默认void,以及binary_function
的便利继承): / p>
template<typename T>
struct minus {
T operator()(const T& lhs, const T& rhs) const {
return operator-(lhs, rhs)
};
};
所以,'functor'(用标准库说法)std::minus
是一种“提升”函数operator-
。我们同样拥有std::plus
,std::multiplies
等等。
现在,假设我想为任意函数实现同样的效果。这是我用宏来做的(对于已知数量的参数,例如2)
#define CONCAT(s1,s2) s1##s2
#define EXPAND_THEN_CONCAT(s1,s2) CONCAT(s1,s2)
#define DEFINE_FUNCTOR(f, ret_type, param1_type, param2_type) \
struct EXPAND_THEN_CONCAT(f,_functor) { \
ret_type operator()(param1_type x, param2_type y) const { \
return f(x, y) \
}; \
};
...但当然我想用C ++ 11方式(或C ++ 14方式,如果有帮助)。我该怎么办?
我有想法以某种方式将f in作为模板参数传递;但是如何让operator()与f具有相同的签名(并使用const标记)?对于一个固定的签名,我认为它不会那么困难,而且代码应该看起来像std::minus
- 但总的来说我无法真正看到它将如何完成。
我曾想过尝试类似于我在函数的“提升调用”中使用的东西:
template<typename F, typename... Parameters>
inline void invoke(const F& f, Parameters... parameters) {
f(parameters...);
}
但是,再次,这不会削减它 - 这将让我得到我喜欢的执行,但不是我喜欢的签名;我需要那个签名......
答案 0 :(得分:4)
std::minus
是类型。它是一个具有operator()
重载的类型,恰好在它给出的参数上调用operator-
。
您是否在询问是否有办法创建可以调用任意函数的类型?这将要求您以某种方式指定调用该类型的函数。向类型提供参数的唯一方法是通过模板参数。
虽然non-type template parameters可能是函数指针,但它们不会像std::minus
那样工作,operator-
通过重载解析等调用#define CREATE_FUNCTOR(f) \
[=](auto&& ...args) -> decltype(auto) \
{ \
return f(std::forward<decltype(args)>(args)...); \
}
。函数指针指向特定函数,而不是重载集。
您似乎想要的是能够指定一个标识符,并获取一个对象,该对象在被调用时将完全调用该标识符,就像您直接调用它一样。这包括重载决议等。
C ++作为一种语言不能做到这一点。论文P0119 (PDF)是添加此类语言功能的提案,但它不处理成员函数。目前还不清楚Kona在2015年的情况如何,如果它出现的话。
你能得到的最接近的是通过C ++ 14 lambdas改进你的宏:
this
这里使用lambda的原因是,如果你在一个成员函数中使用它,如果f
碰巧是一个成员函数,lambda将能够捕获myprj/templates/index.html
<h1>${_('Home')}</h1>
。它也将被视为封闭类型的朋友。
当然,这会创建一个值,而不是一个类型。
答案 1 :(得分:1)
这是你想要的吗?
#include <iostream>
#include <utility>
template <typename Sig, Sig& f>
struct func_wrapper;
template <typename R, typename... Args, R(&f)(Args...)>
struct func_wrapper<R(Args...), f> {
template <typename... Ts>
R operator ()(Ts&&... xs) const {
return f(std::forward<Ts>(xs)...);
}
};
int func(int x) {
return x;
}
int main() {
func_wrapper<decltype(func), func> f;
std::cout << f(1) << std::endl;
}