Strange error C2275 ... illegal use of this type as an expression with member function template and lambdas
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_ru开发者_Python百科ntime_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.
That would look like a compiler limitation. It compiles fine on gcc 4.6 with --std=c++0x
In case anyone else wants to try, I did some work to actually copy/past this into a proper, 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;
}
精彩评论