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)};
posted @ 2019-12-31 10:10  刘-皇叔  阅读(272)  评论(0编辑  收藏  举报