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

时间:2011-06-21 22:13:32

标签: c++ templates lambda c++11

摘要

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

详情

首先,我有一个基类,可以将function个实例保存在vector中。只有派生类可以通过调用functionvectoradd_external实例添加function个实例。可以通过调用invoke_externals公开调用所有function个实例。派生类将lambdas添加为invoke_internal个实例。那些lambdas将依次用另一个“内部”lambda调用基类函数模板invoke_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_; }; 中执行“内部”lambda时将被显式捕获的异常类型:

logic_error

然后我有两个琐碎的自由函数抛出runtime_errorinvoke_internal例外。这些函数将用于void throws_logic_error() { throw logic_error(""); } void throws_runtime_error() { throw runtime_error(""); }

中调用的“内部”lambda
derived

add_external类构造函数中,添加了两个lambdas invoke_internal。每个lambdas都用“内部”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(); }); }); } };

derived

要将所有这些组合在一起,invoke_externals将被实例化,并调用derived来调用int wmain(int, wchar_t*[]) { derived().invoke_externals(); return 0; } 构造函数中添加的“外部”lambdas。那些“外部”lambdas将反过来调用“内部”lambdas,并且将明确地捕获抛出的异常:

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

问题

但是,上面没有编译:

invoke_internal

...是针对derived构造函数中invoke_internal的调用而发出的。

如果我从base移出base并使其成为免费功能,则会进行编译。

问题

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

注意:将违规函数移出{{1}}并非最佳,因为在我的现实生活场景中,函数确实以不同的方式使用其类的状态。

2 个答案:

答案 0 :(得分: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(); }); });
}   //                       ^^^^^^^^^^^^^^

不要问我为什么。一般来说,你得到的错误意味着,使用类型的模板没有被检测到。

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

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

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

答案 1 :(得分:3)

这看起来像编译器限制。它使用--std = c ++ 0x

在gcc 4.6上编译正常

如果有其他人想尝试,我做了一些工作来实际复制/过去这个正确的,编译,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;
}