我正在尝试编写一个模仿三件事的函数:
代码如下所示:
#include <iostream>
#include <typeinfo>
using namespace std;
// Assume that this function is in a library. Can't be modified.
void bar(int x, int y) {
cout << x << endl;
cout << y << endl;
}
// My code is below:
template <typename Type1, typename Type2, void (*fn)(Type1, Type2)>
void foo(Type1 x1, Type2 x2) {
fn(x1,x2);
}
int main() {
foo<int, int, &bar>(1,2);
}
代码有效,但我不满意我的模板必须包含<int, int, &bar>
。我希望编译器会发现bar有int, int
作为参数并计算出来。
我尝试首先列出函数,然后在类型声明中使用,但在声明中,Type1
在函数原型中未被识别,因为它稍后在同一原型中定义。
有优雅的解决方案吗?
编辑:我绝对不想在堆栈上传递指向bar
的指针。我想在bar
上模仿。参数应该只是(1, 2)
。
Edit2:就此而言,我的意思是我想写foo<&bar>(1,2)
。
答案 0 :(得分:3)
这是我没有将函数作为参数传递的解决方案:
void bar(int a, int b) {
cout << a << " " << b << endl;
}
template <class F, F *fn>
struct Foo {
template <class... Args>
static decltype(auto) foo(Args &&... args) {
return fn(std::forward<Args>(args)...);
}
};
int main() {
Foo<decltype(bar), bar>::foo(1, 2);
return 0;
}
正如你所看到的那样,你必须两次写bar
,一次写它的类型,一次它的价值,但我认为这是一个小小的不便。
或简单版本(如果你不能使用c ++ 11)
template <class F, F* fn>
struct Foo {
template <class T1, class T2>
static void foo(T1 t1, T2 t2) {
fn(t1, t2);
}
};
对于那些不介意将函数obj作为参数传递的人:
选项1:
template <class T1, class T2>
void foo(T1 x1, T2 x2, void (*fn)(T1, T2)) {
fn(x1, x2);
}
foo(1, 2, bar);
选项2:
template <class T1, class T2, class F = void(*)(T1, T2)>
void foo(T1 x1, T2 x2, F fn)) {
fn(x1, x2);
}
foo(1, 2, bar);
选项3:
template <class T1, class T2, class F>
void foo(T1 x1, T2 x2, F fn)) {
fn(x1, x2);
}
foo(1, 2, bar);
选项3b(真实交易):
template <class T1, class T2, class F>
void foo(T1 &&x1, T2 &&x2, F &&fn)) {
std::forward<F>(fn)(std::forward(x1), std::forward(x2));
}
foo(1, 2, bar);
选项4(真实的交易)(好......取决于你需要的东西)
template <class F, class... Args>
decltype(auto) foo(F &&fn, Args &&... args) {
return std::forward<F>(fn)(std::forward<Args>(args)...);
}
答案 1 :(得分:0)
您甚至可以避免使用包含该值的临时bar
键入struct
两次。该结构将由任何体面的编译器优化,bar
将不会在堆栈上传递,尽管作为参数传递给foo
:
template <typename Fn>
struct FooT {
Fn &fn;
FooT(Fn fn):fn(fn){}
operator Fn *() {return fn;}
};
template <typename Fn>
inline FooT<Fn> foo(Fn *fn) {return FooT<Fn>(fn);}
int main() {
foo(bar)(1,2);
}
注意:转换为Fn *
可以直接调用fn
,无需任何参数转发。如果需要,也可以使用模板operator ()
传递/转发参数来调用它,但这似乎更简单且有效。如果您需要在调用fn
之前或之后执行更多操作,模板化实现可能会很方便。我不是前瞻性的论点,只是传递它们,为了保持简单,如果有必要,这可以很容易地改变:
template <typename Fn>
struct FooT {
Fn &fn;
FooT(Fn fn):fn(fn){}
template <typename Type1, typename Type2>
void operator ()(Type1 x1, Type2 x2) {
fn(x1,x2);
}
};
Visual Studio 2012生成的代码,禁用整个程序优化,仅扩展内联(/ Ob1):
foo(bar)(1,2);
011E16F0 push 2
011E16F2 push 1
011E16F4 call bar (011E13D0h)
011E16F9 add esp,8