假设我有一个functionProxy带有泛型参数的函数function并调用它operator():
template< typename Function > void functionProxy( Function function ) {
function();
}
Run Code Online (Sandbox Code Playgroud)
传递给它的对象可能是:
一个仿函数:
struct Functor {
void operator()() const {
std::cout << "functor!" << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)功能:
void function( ) {
std::cout << "function!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)一个(C++ 0x)lambda函数:
[](){ std::cout << "lambda!" << std::endl; }
Run Code Online (Sandbox Code Playgroud)int main( )
{
functionProxy( Functor() );
functionProxy( function );
functionProxy( [](){ std::cout << "lambda!" << std::endl; } );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器将能够内联function中 …
在下面的代码示例中,调用foo工作,而调用bar失败.
如果我注释掉调用bar,代码编译,告诉我自己的定义bar是好的.那怎么会bar被正确调用?
#include <iostream>
using namespace std;
int multiply(int x, int y)
{
return x * y;
}
template <class F>
void foo(int x, int y, F f)
{
cout << f(x, y) << endl;
}
template <class F>
void bar(int x, int y)
{
cout << F(x, y) << endl;
}
int main()
{
foo(3, 4, multiply); // works
bar<multiply>(3, 4); // fails
return 0;
}
Run Code Online (Sandbox Code Playgroud) 下面的代码被VC++ 2012拒绝,"错误C2207:'A :: bar':类模板的成员无法获取函数类型".
int Hello(int n)
{
return n;
}
template<class FunctionPtr>
struct A
{
A(FunctionPtr foo)
: bar(foo)
{}
FunctionPtr bar;
};
int main()
{
A<decltype(Hello)> a(Hello);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么?
在回答时如何编写看起来像方法的lambda表达式?我试图通过利用这样一个事实将无捕获的lambda变成一个成员函数指针,因为C++ 17,无捕获的lambdas有一个constexpr转换操作符到它们的函数指针类型.
所以我提出了一个问题:
template<void(*)()> struct A{};
int main()
{
A<static_cast<void(*)()>([]{})>{}; // 1
constexpr auto fp = static_cast<void(*)()>([]{});
A<fp>{}; // 2
}
Run Code Online (Sandbox Code Playgroud)
现在,这在clang(从5.0.0开始)编译,但gcc(> = 7.2)抱怨:
error: lambda-expression in template-argument
A<static_cast<void(*)()>([]{ /*whatever*/ })>{}; // 1
^
error: 'main()::<lambda()>::_FUN' is not a valid template argument for type 'void (*)()' because 'static constexpr void main()::<lambda()>::_FUN()' has no linkage
A<fp>{}; // 2
Run Code Online (Sandbox Code Playgroud)
问题是,谁是对的?
我有一个接受函数作为参数的模板.
当我尝试传递lambda表达式时,它不会编译.
typedef int (*func)(int a);
template <func foo>
int function(int a)
{
foo(a);
}
int test(int a)
{
return a;
}
int main()
{
function<test>(1); // ---> this is ok
auto lambda = [](int a) -> int { return a; };
function<lambda>(1); // ---> this is wrong, why?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
我正在尝试创建一个通用的包装器函数,它将函数作为模板参数,并使用与该函数相同的参数作为其参数.例如:
template <typename F, F func>
/* return type of F */ wrapper(Ts... Args /* not sure how to get Ts*/)
{
// do stuff
auto ret = F(std::forward<Ts>(args)...);
// do some other stuff
return ret;
}
Run Code Online (Sandbox Code Playgroud)
解决方案需要可以转换为具有相同类型的函数指针,func以便我可以将其传递给C api.换句话说,解决方案需要是一个函数而不是一个函数对象.最重要的是,我需要能够在包装函数中完成工作.
如果内联评论不清楚,我希望能够做如下的事情:
struct c_api_interface {
int (*func_a)(int, int);
int (*func_b)(char, char, char);
};
int foo(int a, int b)
{
return a + b;
}
int bar(char a, char b, char c)
{
return a + b * c; …Run Code Online (Sandbox Code Playgroud) 想象一下,我有以下免费功能和仿函数:
void myFreeFunction(void)
{
cout << "Executing free function" << endl;
}
struct MyFunctor
{
void operator()(void)
{
cout << "Executing functor" << endl;
}
};
Run Code Online (Sandbox Code Playgroud)
正如这个答案所描述的,我可以将我的函数或仿函数作为模板参数传递给另一个函数:
template <typename F>
void doOperation(F f)
{
f();
}
Run Code Online (Sandbox Code Playgroud)
然后打电话:
doOperation(myFreeFunction);
doOperation(MyFunctor());
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但是,如果我想要以下内容:
template<typename Callback>
class MyClass
{
private:
Callback mCallback;
public:
MyClass(){}
void execute()
{
mCallback();
}
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我在声明类时指定函数/函子,但是直到稍后才调用它.它适用于仿函数:
MyClass<MyFunctor> myClass1;
myClass1.execute();
Run Code Online (Sandbox Code Playgroud)
但不适用于功能:
MyClass<myFreeFunction> myClass2;
myClass2.execute();
Run Code Online (Sandbox Code Playgroud)
编译说:
错误C2923:'MyClass':'myFreeFunction'不是参数'Callback'的有效模板类型参数
这是公平的......但你会如何构建这个?
注意:我知道std :: function并且最终可能会使用它.它虽然速度慢得多,但我正在考虑所有选择.
谢谢,
大卫
关于作为模板参数传递的函数,Ben Supnik提供的社区wiki答案讨论了内联实例化函数模板的问题.
在那个答案是以下代码:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b,);
}
int add(int a, b) { return a + b; }
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
Run Code Online (Sandbox Code Playgroud)
答案继续这样说(关于实例化函数模板的最后一行do_op):
显然这不是内联.
我的问题是:为什么很明显这不是内联的?
我必须为我制作的一些非常复杂的对象重载基本的算术运算符.到目前为止,我已成功实施operator*; 现在我需要operator+等等.代码operator*非常大,但是operator*和operator+我之间的唯一区别在于我使用的一行+而不是*一些复杂的数字.这一行将在一个被多次调用的循环内部,所以我希望它有效,这似乎意味着没有函数指针.(如我错了请纠正我.)
这似乎是模板的完美用法.但我对正确的语法感到茫然.我在ComplicatedObject类定义中思考这样的事情:
template <typename ComplexBinaryOp>
ComplicatedObject BinaryOp(const ComplicatedObject& B) const {
// Do lots of stuff
for(unsigned int i=0; i<OneBazillion; ++i) {
// Here, the f[i] are std::complex<double>'s:
C.f[i] = ComplexBinaryOp(f[i], B.f[i]);
}
// Do some more stuff
return C;
}
inline ComplicatedObject operator*(const ComplicatedObject& B) const {
return BinaryOp<std::complex::operator*>(B);
}
inline ComplicatedObject operator+(const ComplicatedObject& B) const {
return BinaryOp<std::complex::operator+>(B);
}
Run Code Online (Sandbox Code Playgroud)
这个问题是相关的:"作为模板参数传递的函数" …
我想描述使用模板优化这里.但是,随着bool模板参数的增加,实例化模板可能会有太多分支.如果你使用更大的枚举而不是bools,它会变得更加冗长.
#include <iostream>
using namespace std;
template <bool b1, bool b2>
int HeavyLoop_impl(int arg)
{
for (int i = 0; i < 10000000; i++)
{
// b1 is known at compile-time, so this branch will be eliminated
if (b1) { arg += 1; }
else { arg += 2; }
// b2 is known at compile-time, so this branch will be eliminated
if (b2) { arg += 10; }
else { arg += 20; }
}
return arg; …Run Code Online (Sandbox Code Playgroud)