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

Summary

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

More details

First I have a base class that stores function instances in vector . Only derived classes can add function instances to this vector by calling add_external . All function instances can be called publicly by invoking invoke_externals . The derived class will add lambdas as function instances. These lambdas, in turn, invoke the invoke_internal base class function template with another "internal" lambdas. The invoke_internal template invoke_internal is the type of exception that will be explicitly caught when the "internal" lambda is invoke_internal 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 throw logic_error and runtime_error . These functions should be used in the "internal" lambda, which is called in invoke_internal :

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

Two lambdas with add_external are added to the constructor of the derived class. Each of these lambdas calls invoke_internal "internal" lmbdas. The first invoke_internal call will explicitly catch logic_error , which will throw throws_logic_error . The second invoke_internal call will explicitly catch the runtime_error that throws_runtime_error throws.

 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 it all together, derived is created and invoke_externals is called to invoke the "external" lambdas added to the derived constructor. These "external" lambdas, in turn, will cause "internal" lambdas, and the thrown exceptions will be clearly caught:

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

Problem

However, the above does not 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 

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

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

Question

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

Note. Moving the violation function from base not optimal, since in my real-life scenario, the function actually uses the state of its class in different ways.

+3
source share
2 answers

Thanks to @sehe's answer, I was able to 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(); }); }); } // ^^^^^^^^^^^^^^ 

Do not ask me why. In general, the error you received means that the template in which this type was used was not detected as such.

Usually this should happen only with dependent types / nested templates and can be enabled with template immediately before the template in question (as shown), which tells the compiler that the template follows (duh). We need this-> before this, because otherwise it will look like an explicit instance that would be wrong in itself:

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

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

+5
source

This will look like a compiler restriction. It compiles on gcc 4.6 with --std = C ++ 0x

In case someone else wants to try, I did some work to actually copy / read this into the correct compiling 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; } 
+3
source

Source: https://habr.com/ru/post/891128/


All Articles