Not the same as but possibly related to this question about static initializers.
Here the first two functions compile fine, and the last one doesn't in vc++ but does in clang and gcc:
class A {
protected:
std::string protected_member = "yay";
public:
void withNormalBlock();
void withFunctionBlock();
void noLambda();
};
void A::withNormalBlock() {
try {
throw std::exception();
} catch (...) {
[this]() {
std::cout << protected_member << std::endl;
}();
}
}
void A::noLambda() try {
throw std::exception();
} catch (...) {
std::cout << protected_member << std::endl;
}
void A::withFunctionBlock() try {
throw std::exception();
} catch (...) {
[this]() {
// this line is the problem:
std::cout << protected_member << std::endl;
}();
}
error C2248: 'A::protected_member' : cannot access protected member declared in class 'A'
)I can't find anything in the standard to suggest that the handler / catch block of a function-try-block should be exempt from function scope or that the lambda's closure type should change. The code compiles if the access type is changed to all public.
What could the root cause be? Is it a bug, or is it something specific to compiler settings that could be changed?
Seems that this is a bug and the lambda in the catch
scope is generated outside class scope. I tried to prove that with typeids but the Visual Studio lambda names are weirdly mangled and the name itself does not prove anything. However, error codes generated by the following snippet show that the names differ:
#include <iostream>
#include <typeinfo>
class Foo {
private:
public:
void testLambda()
try {
auto tryScope = [this]() {};
void (*p)() = tryScope;
}
catch(...)
{
auto catchScope = [this]() {};
void (*p)() = catchScope;
}
};
Error output:
(10): error C2440: 'initializing' : cannot convert from 'Foo::testLambda::<lambda_8a3a8afea7359de4568df0e75ead2a56>' to 'void (__cdecl *)(void)'
(15): error C2440: 'initializing' : cannot convert from '<lambda_8cbc08e7748553fb5ae4e39184491e92>' to 'void (__cdecl *)(void)'
I'd guess it is a compiler bug. It reports the same error in VS2015 as well. Curiously, an attempt to explicitly simulate the functionality of lambda works without any issues in VS2015
class A
{
protected:
std::string protected_member = "yay";
public:
void withFunctionBlock();
};
void A::withFunctionBlock() try
{
throw std::exception();
}
catch (...)
{
struct Closure {
Closure(A *this_) : this_(this_) {}
void operator ()() const { std::cout << this_->protected_member << std::endl; }
A *this_;
};
Closure(this)();
}
I wonder what VS C++ compiler does differently under the hood...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With