如果定义了QT_NO_CAST_FROM_ASCII,为什么VisualStudio不允许我在lambda中使用QStringLiteral?

时间:2014-04-15 22:46:24

标签: c++ visual-studio-2010 qt visual-c++ qstring

我们正在通过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 *

0 个答案:

没有答案