Clang vs GCC:枚举使用中的单冒号

Clang vs GCC: Single-colon in Enum usage

以下代码使用 g++ -std=c++11 编译,但不使用 clang++ -std=c++11

问题

  1. 在此上下文中,单冒号 "operator" 的含义是什么?
    • Clarification/Edit: GCC 是如何解释代码的?
  2. 如何让 GCC 不编译这段代码? (这里假设 Clang 遵循 C++ 标准。)有没有标志?

代码

g++ -std=c++11 main.cppclang++ -std=c++11 main.cpp 编译。我正在使用 GCC 4.8 和 Clang 6.0.0(主干)。

#include <iostream>
#include <vector>

enum Dir { LEFT, RIGHT };

int main(int argc, char** argv) {
  // Interesting line: Notice the single ':'
  std::vector<Dir> dirs = { Dir:LEFT, Dir:RIGHT };

  for (auto v: dirs) {
    std::cout << v << std::endl;
  }
  return 0;
}

Clang 错误消息

为了完整性和可搜索性:

 $ clang++ -std=c++11 main.cpp                                                                                                                                                                                            

main.cpp:7:29: warning: use of GNU old-style field designator extension [-Wgnu-designator]
  std::vector<Dir> dirs = { Dir:LEFT, Dir:RIGHT };
                            ^~~~
                            .Dir = 
main.cpp:7:39: warning: use of GNU old-style field designator extension [-Wgnu-designator]
  std::vector<Dir> dirs = { Dir:LEFT, Dir:RIGHT };
                                      ^~~~
                                      .Dir = 
main.cpp:7:20: error: no matching constructor for initialization of 'std::vector<Dir>'
  std::vector<Dir> dirs = { Dir:LEFT, Dir:RIGHT };
                   ^      ~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:269:7: note: candidate constructor not viable: cannot convert argument of incomplete type 'void' to 'std::vector::size_type' (aka 'unsigned long') for 1st argument
      vector(size_type __n, const allocator_type& __a = allocator_type())
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:281:7: note: candidate constructor not viable: cannot convert argument of incomplete type 'void' to 'std::vector::size_type' (aka 'unsigned long') for 1st argument
      vector(size_type __n, const value_type& __value,
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:331:7: note: candidate constructor not viable: cannot convert argument of incomplete type 'void' to 'const std::vector<Dir, std::allocator<Dir> >' for 1st argument
      vector(const vector& __x, const allocator_type& __a)
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:340:7: note: candidate constructor not viable: cannot convert argument of incomplete type 'void' to 'std::vector<Dir, std::allocator<Dir> >' for 1st argument
      vector(vector&& __rv, const allocator_type& __m)
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:364:7: note: candidate constructor not viable: cannot convert argument of incomplete type 'void' to 'initializer_list<std::vector<Dir, std::allocator<Dir> >::value_type>'
      (aka 'initializer_list<Dir>') for 1st argument
      vector(initializer_list<value_type> __l,
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:392:9: note: candidate template ignored: substitution failure [with _InputIterator = void]: no type named 'iterator_category' in 'std::iterator_traits<void>'
        vector(_InputIterator __first, _InputIterator __last,
        ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:256:7: note: candidate constructor not viable: requires single argument '__a', but 2 arguments were provided
      vector(const allocator_type& __a)
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:310:7: note: candidate constructor not viable: requires single argument '__x', but 2 arguments were provided
      vector(const vector& __x)
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:327:7: note: candidate constructor not viable: requires single argument '__x', but 2 arguments were provided
      vector(vector&& __x) noexcept
      ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:248:7: note: candidate constructor not viable: requires 0 arguments, but 2 were provided
      vector()
      ^
2 warnings and 1 error generated.

要使 gcc 拒绝代码,请使用 -pedantic 开关。

冒号是GNU模式下的扩展:X:Y表示.X = Y,是指定的初始化器。 (这些都不在 ISO C++ 中支持)。


gcc 也接受以下代码:

std::vector<int> v = { .a = 1, .b = 2 };

但拒绝代码:

struct S { int p, q; S() {} };
S s = { .a = 1, .b = 2 };   // S has no member named 'a'

我猜这是一个编译器错误;关于初始化 a std::vector<int> 的某些事情会导致它忽略指定初始化程序的名称。请注意,这类事情是非标准功能的标志:它们不在标准中的原因通常是它们不能与其他语言功能很好地融合,而且没有人能提出一个明智的建议来处理所有问题可能的情况。