为什么成员函数尝试块处理程序中的 lambda(捕获 'this')不能访问 VC++ 2013 中的私有数据成员?
Why can't a lambda (capturing 'this') in a member function-try-block handler access private data members in VC++ 2013?
与 this question about static initializers 不同但可能相关。
前两个函数编译正常,最后一个函数在 vc++ 中不编译,但在 clang 和 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;
}();
}
- in clang(确定)
- in gcc(确定)
- in vc++ (
error C2248: 'A::protected_member' : cannot access protected member declared in class 'A'
)
- vc++ 2015 -- 同样交易
我在标准中找不到任何建议 function-try-block 的处理程序/catch 块应该从函数范围中豁免或者 lambda 的闭包类型应该改变的建议。如果访问类型更改为所有 public.
,代码将编译
根本原因可能是什么?它是错误,还是特定于可以更改的编译器设置?
我猜这是一个编译器错误。它在 VS2015 中也报告相同的错误。奇怪的是,尝试显式模拟 lambda 的功能在 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)();
}
我想知道 VS C++ 编译器在幕后有什么不同...
这似乎是一个错误,catch
范围内的 lambda 是在 class 范围外生成的。我试图用 typeids 来证明这一点,但是 Visual Studio lambda 名称被奇怪地破坏了,名称本身并不能证明任何东西。但是,以下代码片段生成的错误代码显示名称不同:
#include <iostream>
#include <typeinfo>
class Foo {
private:
public:
void testLambda()
try {
auto tryScope = [this]() {};
void (*p)() = tryScope;
}
catch(...)
{
auto catchScope = [this]() {};
void (*p)() = catchScope;
}
};
错误输出:
(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)'
与 this question about static initializers 不同但可能相关。
前两个函数编译正常,最后一个函数在 vc++ 中不编译,但在 clang 和 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;
}();
}
- in clang(确定)
- in gcc(确定)
- in vc++ (
error C2248: 'A::protected_member' : cannot access protected member declared in class 'A'
) - vc++ 2015 -- 同样交易
我在标准中找不到任何建议 function-try-block 的处理程序/catch 块应该从函数范围中豁免或者 lambda 的闭包类型应该改变的建议。如果访问类型更改为所有 public.
,代码将编译根本原因可能是什么?它是错误,还是特定于可以更改的编译器设置?
我猜这是一个编译器错误。它在 VS2015 中也报告相同的错误。奇怪的是,尝试显式模拟 lambda 的功能在 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)();
}
我想知道 VS C++ 编译器在幕后有什么不同...
这似乎是一个错误,catch
范围内的 lambda 是在 class 范围外生成的。我试图用 typeids 来证明这一点,但是 Visual Studio lambda 名称被奇怪地破坏了,名称本身并不能证明任何东西。但是,以下代码片段生成的错误代码显示名称不同:
#include <iostream>
#include <typeinfo>
class Foo {
private:
public:
void testLambda()
try {
auto tryScope = [this]() {};
void (*p)() = tryScope;
}
catch(...)
{
auto catchScope = [this]() {};
void (*p)() = catchScope;
}
};
错误输出:
(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)'