我之前没有看到过这种奇怪的C ++,这让我有点混乱。
我有以下课程:
class KeyValuesParser
{
public:
explicit KeyValuesParser(const QByteArray &input);
QJsonDocument toJsonDocument(QString* errorString = nullptr);
// ...
};
我正试图在Qt单元测试中使用它:
const char* testData = "...";
KeyValuesParser parser(QByteArray(testData));
QJsonDocument doc = parser.toJsonDocument();
这会产生以下编译错误:
Member reference base type 'KeyValuesParser(QByteArray)' is not a structure or union.
但是,如果我在堆栈上创建字节数组然后将其传入,而不是传递一个临时的,那么一切都编译好了:
const char* testData = "...";
QByteArray testByteArray(testData)
KeyValuesParser parser(testByteArray);
QJsonDocument doc = parser.toJsonDocument();
我认为这可能是一些奇怪的黑魔法需要explicit
关键字(这就是我添加它的原因),但这没有任何区别。谁能解释一下这里发生了什么?
答案 0 :(得分:1)
NB。这是Jonas在我附近回答的补充。
你想要做的是将rvalue绑定到左值引用,这在C ++标准中是不允许的。在你的第二个例子中 - 你正确地通过引用传递左值,这就是它工作的原因。
将rvalue绑定到左值引用是Visual C ++扩展,g ++根本不能这样做,clang可以用-fms-extensions
来做答案 1 :(得分:0)
该行
KeyValuesParser parser(QByteArray(testData));
不是对象声明。它是函数的函数声明,返回KeyValuesParser并获取QByteArray参数。
这称为Most Vexing Parse(链接转到维基百科,你也可以在StackOverflow上找到很多)。为了简短起见,如果有疑问,C ++标准更喜欢函数声明,因为otherwise it would be hard to declare functions at all。
答案 2 :(得分:0)
如上所述,这是一个最令人烦恼的解析"问题。 c ++ 11为我们带来了两个解决方案:auto和括号初始化:
// use auto to turn the expression unambiguously into an rvalue
// without having to mention the class name twice
int main()
{
const char* testData = "...";
auto parser = KeyValuesParser(QByteArray(testData));
auto doc = QJsonDocument(parser.toJsonDocument());
}
// or use brace initialisation to avoid the parse ambiguity
//
int main2()
{
const char* testData = "...";
KeyValuesParser parser{ QByteArray(testData) };
QJsonDocument doc{ parser.toJsonDocument() };
}
// another solution:
const char* testData = "...";
auto doc = QJsonDocument(KeyValuesParser(QByteArray(testData)).toJsonDocument());
// yet another
const char* testData = "...";
auto doc = QJsonDocument { KeyValuesParser { QByteArray(testData) }.toJsonDocument() };