Skip to content

Syntax ambiguity in initialization with round parenthese

Direct initialization、Value initialization 与 function declaration的歧义

我们知道Direct initialization、Value initialization的syntax是非常类似的,区别在于 Direct initialization 带参而后者不带参,可以看到,它们的syntax 和 function declaration是非常类似的,因此,就导致了歧义。

1、cppreference Direct initialization 中,给出的如下syntax

T object ( arg );
T object ( arg1, arg2, ... );

可以看到,它和function declaration是非常类似的。

cppreference Direct initialization

In case of ambiguity between a variable declaration using the direct-initialization syntax (1) (with round parentheses) and a function declaration, the compiler always chooses function declaration. This disambiguation rule is sometimes counter-intuitive and has been called the most vexing parse.

#include <iterator>
#include <string>
#include <fstream>
int main()
{
    std::ifstream file("data.txt");
    // the following is a function declaration:
    std::string str(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
    // it declares a function called str, whose return type is std::string,
    // first parameter has type std::istreambuf_iterator<char> and the name "file"
    // second parameter has no name and has type std::istreambuf_iterator<char>(),
    // which is rewritten to function pointer type std::istreambuf_iterator<char>(*)()

    // pre-c++11 fix: extra parentheses around one of the arguments
    std::string str1((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    // post-C++11 fix: list-initialization for any of the arguments
    std::string str2(std::istreambuf_iterator<char> { file }, { });
}
// g++ test.cpp -pedantic -Wall -Wextra

NOTE:

在 "g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28)" 中,上述code是能够正常编译通过的值,只有如下警告:

test.cpp: 在函数‘int main()’中:
test.cpp:17:24: 警告:extended initializer lists only available with -std=c++11 or -std=gnu++11 [默认启用]
  std::string str2(std::istreambuf_iterator<char> { file }, { });
                        ^
test.cpp:17:58: 警告:extended initializer lists only available with -std=c++11 or -std=gnu++11 [默认启用]
  std::string str2(std::istreambuf_iterator<char> { file }, { });

Similarly, in the case of an ambiguity between a expression statement with a function-style cast expression (3) as its leftmost subexpression and a declaration statement, the ambiguity is resolved by treating it as a declaration. This disambiguation is purely syntactic: it doesn't consider the meaning of names occurring in the statement other than whether they are type names.

NOTE:

1、上面这段话没有说清楚"declaration statement"到底是什么?下面的例子,我也没有明白L(n);的含义。

struct M
{
};
struct L
{
    L(M&){}
};

M n;
void f()
{
    M (m); // declaration, equivalent to M m;
    L(n); // ill-formed declaration
    L (l)(m); // still a declaration
}
int main()
{

}
// g++ test.cpp -pedantic -Wall -Wextra

NOTE:

编译报错如下 :

test.cpp: 在函数‘void f()’中:
test.cpp:13:5: 错误:对‘L::L()’的调用没有匹配的函数
  L(n); // ill-formed declaration

下面是正确的写法:

struct M
{
};
struct L
{
  L(M&)
  {
  }
};

M n;
void f()
{
  M (m); // declaration, equivalent to M m;
  L { n }; 
  L (l)(m); // still a declaration
}
int main()
{

}
// g++ test.cpp -pedantic -Wall -Wextra --std=c++11

cppreference Value initialization (since C++03)

The syntax T object(); does not initialize an object; it declares a function that takes no arguments and returns T. The way to value-initialize a named variable before C++11 was T object = T();, which value-initializes a temporary and then copy-initializes the object: most compilers optimize out the copy in this case.