(为什么)这是一个令人烦恼的解析示例吗?
(Why) Is this an example of a vexing parse?
这是C++中令人烦恼的解析示例吗?
#include <pthread.h>
#include <iostream>
class ScopeLock
{
public:
ScopeLock(pthread_mutex_t& m)
: mrMutex(m)
{
pthread_mutex_lock(&mrMutex);
}
~ScopeLock()
{
pthread_mutex_unlock(&mrMutex);
}
protected:
pthread_mutex_t& mrMutex;
};
class Foo
{
public:
Foo()
{
pthread_mutex_init(&m_, NULL);
}
~Foo()
{
pthread_mutex_destroy(&m_);
}
void Func()
{
ScopeLock(m_); // Is this a vexing parse?
std::cout << __FUNCTION__ << std::endl;
}
protected:
pthread_mutex_t m_;
};
int main(int argc, char* argv[])
{
Foo foo;
foo.Func();
return 0;
}
输出:
>g++ main.cpp
main.cpp: In member function u2018void Foo::Func():
main.cpp:37:17: error: no matching function for call to 'ScopeLock::ScopeLock()'
ScopeLock(m_);
^
main.cpp:37:17: note: candidates are:
main.cpp:7:3: note: ScopeLock::ScopeLock(pthread_mutex_t&)
ScopeLock(pthread_mutex_t& m)
^
main.cpp:7:3: note: candidate expects 1 argument, 0 provided
main.cpp:4:7: note: ScopeLock::ScopeLock(const ScopeLock&)
class ScopeLock
^
main.cpp:4:7: note: candidate expects 1 argument, 0 provided
我认为编译器失败了,因为它试图创建一个没有 ctor 参数的ScopeLock
对象(名为 m_),并正确识别出唯一的ScopeLock
ctor 将一个pthread_mutex_t&
作为参数——这是正确的吗?
不过,为什么这是一个令人烦恼的解析(如果是的话)?为什么第 37 行没有被解释为创建带有 ctor 参数m_
的匿名ScopeLock
对象?
如果上面是一个令人烦恼的解析示例,为什么下面的不是烦人的解析?
#include <iostream>
#include <string>
class Foo
{
public:
Foo()
{
pStr = "Foo";
}
~Foo()
{
}
void Func()
{
const std::string& rStr = std::string(pStr);
std::cout << rStr << std::endl;
}
protected:
const char* pStr;
};
int main(int argc, char* argv[])
{
Foo foo;
foo.Func();
return 0;
}
编译和输出:
>g++ main.cpp
>./a.out
Foo
>
第二个代码块似乎与第一个代码块非常相似。那么,为什么编译器不将第 18 行视为创建名为pStr
的没有 ctor 参数的std::string
呢?rStr
cout
导致"Foo"实际上表明匿名std::string
是用const char*
参数创建的。
如果有人能在这里阐明,我将不胜感激。谢谢。
更新我刚刚注意到在第一个代码块中更改了这一点:
ScopeLock(m_); // Is this a vexing parse?
对此:
const ScopeLock& rSl = ScopeLock(m_); // Is this a vexing parse?
导致编译通过。因此,将匿名对象转换为右值可以解决令人烦恼的解析问题吗?我不清楚。
另一方面,在第二个代码块中,更改以下内容:
const std::string& rStr = std::string(pStr);
对此:
std::string(pStr);
编译就好了。但是,生成的pStr
cout
为空。我认为这证实了编译器实际上是在使用默认构造函数创建一个名为pStr
的std::string
。所以实际上这类似于它在第一个代码块中尝试做的事情。
如果有人能确认我的猜测是否正确,我将不胜感激。
"最烦人的解析"的"规范"含义是指对象声明和函数声明之间的歧义。
在你的例子中,你有一个不同的歧义:对象声明和函数式强制转换之间的歧义(更正式地说:显式类型转换的函数表示法,参见 5.2.3)。后一种歧义被解决,有利于对象声明。因此错误。编译器将代码视为简单
代码ScopeLock m_;
这使得它抱怨缺少默认构造函数。
6.8 歧义解决
1涉及表达式语句和声明的语法存在歧义:以函数样式显式类型转换 (5.2.3) 作为其最左侧子表达式的表达式语句可能与第一个声明符以 (.在这些情况下,声明是声明。
您是否要将其称为"最令人烦恼的解析"的另一种风格取决于您。
有许多不同的方法可以使编译器将其解释为表达式而不是声明。您也可以这样做
0, ScopeLock(m_);
或作为
(ScopeLock(m_));
37 行没有被解释为使用 ctor 参数创建匿名
ScopeLock
对象m_
?
这是因为标准有一条规则,如果代码具有可以解释为声明或函数调用的结构,则选择声明处理。
它不担心作为声明的处理是否会导致以后的错误。
如果您考虑一下,回退到完全不同的解释会导致在代码维护期间出现一些非常讨厌的远距离操作结果。 想象一下,如果你写了这段代码,它被接受为函数样式转换,后来有人添加了一个默认构造函数......
尝试替换ScopeLock(m_);
到ScopeLock s(m_);
。对象需要其名称。
-
也许编译器认为ScopeLock(m_)
是ScopeLock m_
.我用 clang 编译,它显示了类似的错误消息。
以下行编译没有任何抱怨:
void Func()
{
ScopeLock(m)(m_);
std::cout << __FUNCTION__ << std::endl;
}
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- (为什么)这是一个令人烦恼的解析示例吗?
- 为什么要在 if 条件下进行令人烦恼的解析
- 为什么这不是一个令人烦恼的解析