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

Strange error C2275 ... illegal use of this type as an expression with member function template and lambdas

本文关键字:成员 函数模板 表达式 lambda 类型 错误 C2275 非法      更新时间:2023-10-16

摘要

由于某种原因,调用 lambda 函数的成员函数模板无法编译并显示错误 C2275 ...非法使用此类型作为表达式,但是当函数被移出为自由函数时,它会正确编译。

首先,我有一个基类,可以将function实例保存在vector中。只有派生类才能通过调用add_external function实例添加到该vector。所有function实例都可以通过调用 invoke_externals 来公开调用。派生类会将 lambda 添加为function实例。这些 lambda 将依次调用基类函数模板,invoke_internal另一个"内部"lambda。要invoke_internal的模板参数是一种异常类型,在invoke_internal中执行"内部"lambda时将被显式捕获:

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_;
};

然后我有两个琐碎的自由函数,它们会抛出logic_errorruntime_error异常。这些函数将在invoke_internal中调用的"内部"lambda中使用:

void throws_logic_error()
{
    throw logic_error("");
}
void throws_runtime_error()
{
    throw runtime_error("");
}

derived 类构造函数中,添加了两个带有 add_external 的 lambda。这些 lambda 中的每一个都用"内部"lmbda 调用invoke_internal。对invoke_internal的第一个调用将显式捕获throws_logic_error将抛出的logic_error。对invoke_internal的第二次调用将显式捕获throws_runtime_error将抛出的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();
            }); 
        });
    }
};

为了将所有这些联系在一起,derived被实例化并调用invoke_externals来调用derived构造函数中添加的"外部"lambda。这些"外部"lambda 将依次调用"内部"lambda,抛出的异常将被显式捕获:

int wmain(int, wchar_t*[])
{
    derived().invoke_externals();
    return 0;
}

问题

但是,以上不编译:

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

。为derived构造函数中对invoke_internal的调用发出。

如果我invoke_internalbase中移出并使其成为自由函数,那么它就会编译。

问题

为什么我收到错误 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(); }); });
}   //                       ^^^^^^^^^^^^^^

不要问我为什么。通常,您收到的错误意味着未检测到使用该类型的模板。

通常,这应该只发生在依赖类型/嵌套模板中,并且可以通过直接在相关模板之前使用template来解决(如图所示(,它告诉编译器模板遵循(duh(。不过,在此之前我们需要this->,否则它看起来像一个显式实例化,这本身就是错误的:

template Foo<int>; // explicitly instantiate the Foo class template for int

现在,这个问题也发生在这里,我只能同意@sehe,这看起来像是编译器的限制。

这看起来像是编译器的限制。它在 gcc 4.6 上编译得很好,使用 --std=c++0x

如果其他人想尝试,我做了一些工作来实际复制/粘贴到适当的编译 TU:

#include <vector>
#include <functional>
#include <stdexcept>
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_;
};
void throws_logic_error()   { throw logic_error("");   }
void throws_runtime_error() { throw runtime_error(""); }
class derived : public base
{
    public:
        derived()
        {
            add_external([this] () { invoke_internal<logic_error>([]() { throws_logic_error(); }); });
            auto g = [this] () { invoke_internal<runtime_error>([]() { throws_runtime_error(); }); };
            add_external(g);
        }
};
int main(int, char*[])
{
    derived().invoke_externals();
    return 0;
}