正在学习C++11的新特性,用非类型模板写了一个函数包装器,我是这样写的:
#include <iostream>
#include <cstdlib>
#include <string>
#include <functional>
void hello() {
std::cout << "Hello, world!\n";
return;
}
template< std::function<void()> i>
void wrapper() {
i();
}
int main() {
std::function<void()> f = hello;
wrapper<f>();
return 0;
}
在VS2013上编译错误,提示是
“std::function”: 非类型模板参数“i”的类型非法
但是当我将wrapper的定义改成
template<void i()>
void wrapper() {
i();
}
将调用改成wrapper<hello>();
之后编译运行就一切正常了。请问这是什么原因?
另外请问std::function除了能包装匿名函数外,还有什么情况下与函数对象或者普通函数指针表现不同呢?谢谢。
黄舟2017-04-17 11:40:24
Because non-type template arguments must be constant expressions. Because everything in the template must be determined at compile time.
http://en.cppreference.com/w/...
Non-type template parameter type is one of the following types (optionally cv-qualified, the qualifiers are ignored)
integral type
enumeration
pointer to object or to function
lvalue reference to object or to function
pointer to member object or to member function
std::nullptr_t (since C++11)
wrapper<f>()
where f is a variable, its value can only be determined during runtime. So the template cannot be compiled and passed. You can't wait until runtime and then Instantiate a wrapper<f>
function and let i point to f, right?
For pointers to functions, the valid arguments are pointers to functions with linkage (or constant expressions that evaluate to null pointer values)., so <void i()>
can compile and pass:
template <typename std::function<void()> *i>
void wrapper() {
(*i)();
}
// 将static 换成 extern 才能通过 MS C++
static std::function<void()> f=hello;
int main() {
wrapper<&f>(); // G++ OK
//下面的不行
constexpr std::function<void()> *f3=&f;
wrapper<f3>();
//顺便说,下面也能编译成功,只是运行当然是segmentfault啦
constexpr std::function<void()> *f2=0;
wrapper<f2>();
return 0;
}
伊谢尔伦2017-04-17 11:40:24
The way you write it, template < std::function<void()> i >
, here i
is obviously a variable, not a type. If you want to declare a type, you should write it as template <typename Func>
. However, if it is declared as a type, wrapper
will of course not work, because i()
is equivalent to instantiating an empty std::function
object and does nothing. In the end, of course, you will not get the effect you want.
Generally speaking, you should implement wrapper
like this to be normal.
template <typename Func>
void wrapper(Func func) {
func();
}
The biggest function of std::function
is to express anonymous functions, especially the anonymous functions in []
that capture the current context variables. When used together with std::shared_ptr
, it will give the illusion of a dynamic language.