C++'s most vexing parse
C++'s most vexing parse 是 Scott Meyers 在其名著《Effective STL》中创造的一个术语。Scott 用这个术语来形容 C++ 标准对于 declaration 语句的消歧义(ambiguity resolution)约定与常人的认知相悖。
形如 Type() 或 Type(name) 的表达在某些情况下具有歧义(syntax ambiguity)。
T1 name(T2());
这个 declaration statement 既可视作声明了一个类型为 T1 名为 name 的 object,并且用一个类型为 T2 的 object 作为其 initilizer(即标准中所谓「an object declaration with a function-style cast as the initializer」),也可视作声明了一个返回值类型为 T1 名为 name 的函数,此函数有一个参数,参数类型为「指向返回值类型为 T2,参数为空的函数的指针」。
C++ 标准规定把这样的 statement 视作函数声明。
T1 name1(T2(name2));
根据 C++ 标准,此时不把 T2(name2) 视为「a function style cast」,而将其视为 T2 name2,这样整个语句就变成:T1 name1(T2 name2);,显然这是个函数声明。
类似地,T1 name1(T2(name2), T3(name3));被视作 T1 name1(T2 name2, T3 name3);
在C++中,以下三种写法都声明了同一个函数:
int f(double d); //@ 声明接受一个double参数d,返回值为int类型的函数
int f(double (d)); //@ 效果一样,参数名外的括号会被忽略
int f(double); //@ 直接省略参数名
类似的,以下三种写法都声明的函数也相同:
int g(double (*pf)()); //@声明接受一个无参数返回类型为double的函数指针pf参数,返回值为int类型的函数
int g(double pf()); //@ 效果一样,pf是隐式函数指针
int g(double ()); //@ 直接省略参数名
举一个栗子:
string my_str; //@ 声明一个 string 类型
vector<int> my_ivec; //@ 声明一个 vector<int> 类型
string my_str(); //@ 声明了一个函数,返回 string
vector<int> my_ivec(); //@ 声明了一个函数,返回 vector<int>
再举一个栗子:
#include <iostream>
class A {
public:
A(const std::string& name){
std::cout << name << std::endl;
}
};
int main()
{
char szTmp[] = "Hello";
A a(std::string(szTmp));
return 0;
}
A a(std::string(szTmp)); 将被解析成函数,解决的办法有:
- 把整个匿名对象用括号括起来:A a((std::string(szTmp)));
- C++ 统一初始化:A a{std::string(szTmp)};