我们正在通过QT_NO_CAST_FROM_ASCII
确保我们的代码库编码安全。使用gcc和clang,一切都运行良好,但在VisualStudio 2010中,我们遇到了以下不寻常的编译问题。
此代码:
#define QT_NO_CAST_FROM_ASCII
#include <QString>
void func()
{
auto f = [] () -> QString
{
QString a = QStringLiteral("Hello.");
return a;
};
QString b = f();
}
生成此错误:
1>example.cpp(7): error C2248: 'QString::QString' : cannot access private member declared in class 'QString'
1> C:\Qt\5.1.1\include\QtCore/qstring.h(691) : see declaration of 'QString::QString'
1> C:\Qt\5.1.1\include\QtCore/qstring.h(207) : see declaration of 'QString'
它抱怨私有的实际构造函数是QString(const char *)
。
QStringLiteral()
是一个复杂的宏,可以完成许多C ++ 11黑魔法,因此旧版VisualC ++会对它产生影响并不奇怪。有趣的是,当QStringLiteral()
被定义时,只在lambda内部使用QT_NO_CAST_FROM_ASCII
时才会出现错误!
编译:
#undef QT_NO_CAST_FROM_ASCII // Note the undef!
#include <QString>
void func()
{
auto f = [] () -> QString
{
QString a = QStringLiteral("Hello.");
return a;
};
QString b = f();
}
就像这样:
#define QT_NO_CAST_FROM_ASCII
#include <QString>
void func()
{
auto f = [] () -> QString
{
QString a = QLatin1String("Hello."); // Note using QLatin1String() instead.
return a;
};
QString b = f();
}
而且:
#define QT_NO_CAST_FROM_ASCII
#include <QString>
void func()
{
QString a = QStringLiteral("Hello."); // Note QStringLiteral() used outside the lambda.
auto f = [&a] () -> QString
{
return a;
};
QString b = f();
}
发生了什么事?这不是一个关键问题;有很多可用的解决方法,但它很奇怪,我不禁想知道为什么。
更新
在发布之前我曾查看QStringLiteral
宏,但在Alf的建议下我完全扩展了它,(格式化后为清晰起见)给出了:
#define QT_NO_CAST_FROM_ASCII
#include <QString>
void func()
{
auto f = [] () -> QString
{
QString a = ( []() -> QString
{
enum { Size = sizeof(L"Hello.")/2 - 1 };
static const QStaticStringData<Size> qstring_literal = { { { { (-1) } }, Size, 0, 0, sizeof(QStringData) }, L"Hello." };
QStringDataPtr holder = { qstring_literal.data_ptr() };
const QString s(holder);
return s;
}()
);
return a;
};
QString b = f();
}
这会生成完全相同的错误,现在建议编译器lambda调用的返回类型为char *
,尽管它明确具有返回类型QString
。但是,进行一次小的更改会导致编译:
#define QT_NO_CAST_FROM_ASCII
#include <QString>
void func()
{
auto f = [] () -> QString
{
auto qsl = []() -> QString
{
enum { Size = sizeof(L"Hello.")/2 - 1 };
static const QStaticStringData<Size> qstring_literal = { { { { (-1) } }, Size, 0, 0, sizeof(QStringData) }, L"Hello." };
QStringDataPtr holder = { qstring_literal.data_ptr() };
const QString s(holder);
return s;
};
QString a = qsl();
return a;
};
QString b = f();
}
所以显然试图直接在lambda定义上调用operator()
只会让编译器混淆我不知道什么。令人抓狂的是,如果QT_NO_CAST_FROM_ASCII
未定义,QString(const char *)
构造函数不再是私有的,可能是编译器以某种方式成功地将它用于lambda调用的结果,尽管lambda没有不返回char *