奇怪的错误C2275 ...非法使用此类型作为具有成员函数模板和lambdas的表达式

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_errorruntime_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_errorthrows_logic_error将抛出.第二次调用invoke_internal将明确地抓住runtime_errorthrows_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_internalderived.

如果我invoke_internal从中移出base并使其成为自由函数,那么它就会编译.

为什么我会收到错误C2275 ...当函数模板是base成员时,非法使用此类型作为表达式

注意:移除违规函数base不是最佳的,因为在我的现实生活场景中,函数实际上以不同的方式使用其类的状态.

Xeo*_*Xeo 5

感谢@ 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这看起来像编译器的限制.