奇怪的错误C2275 ...非法使用此类型作为一个表达式与成员函数模板和lambdas [英] Strange error C2275 ... illegal use of this type as an expression with member function template and lambdas

查看:123
本文介绍了奇怪的错误C2275 ...非法使用此类型作为一个表达式与成员函数模板和lambdas的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要



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



/ strong>



首先,我有一个基类,在向量中保留 function 。只有派生类可以通过调用 add_external 向量添加 function c>。所有 function 实例可以通过调用 invoke_externals 来公开调用。派生类将添加lambdas作为 function 实例。那些lambdas将依次调用基类类函数模板 invoke_internal 与另一个内部lambda。 invoke_internal 中的模板参数是在 invoke_internal 中执行内部lambda时将被显式捕获的异常类型:

  using namespace std; 

class base
{
public:
void invoke_externals()
{
for(auto it = funcs_.begin != 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 >> funcs_;
};

然后我有两个琐碎的自由函数,引发 logic_error runtime_error 异常。这些函数用于 invoke_internal 中调用的内部lambda:

  void throws_logic_error()
{
throw logic_error();
}

void throws_runtime_error()
{
throw runtime_error();
}



<类构造函数,两个lambdas添加 add_external 。每个这些lambdas调用 invoke_internal 与innerlmbdas。第一次调用 invoke_internal 将显式捕获 logic_error throws_logic_error 会抛出。第二次调用 invoke_internal 将显式捕获 runtime_error throws_runtime_error 将抛出。

 类派生:public base 
{
public:
derived )
{
add_external([this]()
{
invoke_internal< logic_error>([]()
{
throws_logic_error $ b});
});

add_external([this]()
{
invoke_internal< runtime_error>([]()
{
throws_runtime_error();
});
});
}
};

将所有这些结合在一起,派生实例化并调用 invoke_externals 以调用在派生构造函数中添加的externallambdas。这些外部lambda将反过来调用内部lambdas和抛出的异常将被明确捕获:

  int wmain int,wchar_t * [])
{
derived()。invoke_externals();

return 0;
}

问题

但是,以上不编译:

 错误C2275:'std :: logic_error':非法使用此类型作为表达式
错误C2275:'std :: runtime_error':非法使用此类型作为表达式

$ b在派生构造函数中对 invoke_internal 的调用发出
$ b <



如果我从 base 移动 invoke_internal 它是一个自由功能,然后它编译。<​​/ p>

问题



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



注意:将违规功能移出 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();});});
} // ^^^^^^^^^^^^^

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



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

  template Foo< int> ;; //显式实例化int类的Foo类模板

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


Summary

For some reason, my member function template that invokes a lambda function fails to compile with error C2275 ... illegal use of this type as an expression, but when the function is moved out to be a free function it compiles correctly.

Details

First I have a base class that keeps function instances in a vector. Only derived classes can add function instances to that vector by calling add_external. All function instances can be publicly invoked by calling invoke_externals. A derived class will add lambdas as function instances. Those lambdas will in turn call the base class function template invoke_internal with another "inner" lambda. The template parameter to invoke_internal is an exception type that will be explicitly caught when executing the "inner" lambda in invoke_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_;
};

Then I have two trivial free functions that throws logic_error and runtime_error exceptions. These functions are to be used in the "inner" lambda that is invoked in invoke_internal:

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

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

In the derived class constructor, two lambdas are added with add_external. Each of those lambdas call invoke_internal with "inner" lmbdas. The first call to invoke_internal will explicitly catch the logic_error that throws_logic_error will throw. The second call to invoke_internal will explicitly catch the runtime_error that throws_runtime_error will throw.

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();
            }); 
        });
    }
};

And to tie all this together, derived is instantiated and invoke_externals is called to invoke the "external" lambdas added in the derived constructor. Those "external" lambdas will in turn invoke the "inner" lambdas and the thrown exceptions will be explicitly caught:

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

    return 0;
}

Problem

However, the above don't compile:

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

...is issued for the calls to invoke_internal in the derived constructor.

If I move invoke_internal out from base and make it a free function, then it compiles.

Question

Why do I get error C2275 ... illegal use of this type as an expression when the function template is a base member?

Note: Moving the offending function out of base isn't optimal since in my real life scenario the function actually do use its class' state in different ways.

解决方案

Thanks to @sehe's answer, I could test this myself on VS2010. The following code works:

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(); }); });
}   //                       ^^^^^^^^^^^^^^

Don't ask me why.Generally, the error that you get means, that the template, where the type was used, was not detected as such.

Normally this should only occur with dependent types / nested templates and can be solved with a template directly before the template in question (as shown), which tells the compiler that a template follows (duh). We need this-> before that though, because else it would look like an explicit instantiation, which would be wrong on its own:

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

Now. strangly, this problem also occurs here and I can only agree with @sehe that this looks like a compiler limitation.

这篇关于奇怪的错误C2275 ...非法使用此类型作为一个表达式与成员函数模板和lambdas的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆