Joh*_*ell 3 c++ lambda templates c++11
摘要
由于某种原因,调用lambda函数的成员函数模板无法使用错误C2275进行编译...非法使用此类型作为表达式,但是当函数移出为自由函数时,它会正确编译.
细节
首先,我有一个基类,将function实例保存在一个vector.只有派生类可以通过调用向其添加function实例.可以通过调用公开调用所有实例.派生类将lambdas添加为实例.那些lambdas将依次用另一个"内部"lambda 调用基类函数模板.模板参数to 是一个异常类型,在执行"内部"lambda时将被显式捕获:vectoradd_externalfunctioninvoke_externalsfunctioninvoke_internalinvoke_internalinvoke_internal
using namespace std;
class base
{
public:
void invoke_externals()
{
for (auto it = funcs_.begin(); it != funcs_.end(); ++it)
{
(*it)();
}
}
protected:
void add_external(function<void(void)> func)
{
funcs_.push_back(func);
}
template <typename T>
void invoke_internal(function<void(void)> func)
{
try
{
func();
}
catch (const T&){}
catch (...){}
}
vector<function<void(void)>> funcs_;
};
Run Code Online (Sandbox Code Playgroud)
然后我有两个琐碎的自由函数抛出logic_error和runtime_error异常.这些函数将在以下调用的"内部"lambda中使用invoke_internal:
void throws_logic_error()
{
throw logic_error("");
}
void throws_runtime_error()
{
throw runtime_error("");
}
Run Code Online (Sandbox Code Playgroud)
在derived类构造函数中,添加了两个lambda add_external.这些lambdas中的每一个都称之为invoke_internal"内在"的lmbdas.第一次调用invoke_internal将明确地抓住logic_error这throws_logic_error将抛出.第二次调用invoke_internal将明确地抓住runtime_error这throws_runtime_error将抛出.
class derived : public base
{
public:
derived()
{
add_external([this]()
{
invoke_internal<logic_error>([]()
{
throws_logic_error();
});
});
add_external([this]()
{
invoke_internal<runtime_error>([]()
{
throws_runtime_error();
});
});
}
};
Run Code Online (Sandbox Code Playgroud)
并将所有这些绑定在一起,derived实例化并invoke_externals调用以调用derived构造函数中添加的"外部"lambdas .那些"外部"lambdas将依次调用"内部"lambdas,并且将明确捕获抛出的异常:
int wmain(int, wchar_t*[])
{
derived().invoke_externals();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题
但是,上面没有编译:
error C2275: 'std::logic_error' : illegal use of this type as an expression
error C2275: 'std::runtime_error' : illegal use of this type as an expression
Run Code Online (Sandbox Code Playgroud)
...是为构造函数中的调用发出invoke_internal的derived.
如果我invoke_internal从中移出base并使其成为自由函数,那么它就会编译.
题
为什么我会收到错误C2275 ...当函数模板是base成员时,非法使用此类型作为表达式?
注意:移除违规函数base不是最佳的,因为在我的现实生活场景中,函数实际上以不同的方式使用其类的状态.
感谢@ sehe的回答,我可以在VS2010上自己测试一下.以下代码有效:
derived()
{ // vvvvvvvvvvvvvv
add_external([this] () { this->template invoke_internal<logic_error>([]() { throws_logic_error(); }); });
add_external([this] () { this->template invoke_internal<runtime_error>([]() { throws_runtime_error(); }); });
} // ^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
不要问我为什么.一般来说,你得到的错误意味着,使用类型的模板没有被检测到.
通常情况下,这应该只发生在依赖类型/嵌套模板中,并且可以template直接在相关模板之前解决(如图所示),它告诉编译器模板后面(duh).我们this->在此之前需要,因为否则它看起来像一个显式的实例化,这本身就是错误的:
template Foo<int>; // explicitly instantiate the Foo class template for int
Run Code Online (Sandbox Code Playgroud)
现在.扼杀,这个问题也出现在这里,我只能同意@sehe这看起来像编译器的限制.