Clang vs GCC: использование двоеточия в Enum

Следующий код компилируется с g++ -std=c++11 но не с clang++ -std=c++11,

Вопросы

  1. Каково значение единственного двоеточия "оператор" в этом контексте?
    • Уточнение / редактирование: как GCC интерпретирует код?
  2. Как я могу заставить GCC не компилировать этот код? (Предполагая, что Clang следует стандарту C++ здесь.) Есть ли флаг для этого?

Код

Компилировать с g++ -std=c++11 main.cpp а также clang++ -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.

1 ответ

Решение

Чтобы 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'

Я думаю, это ошибка компилятора; кое-что об инициализации std::vector<int> заставляет его игнорировать имена назначенных инициализаторов. Обратите внимание, что такого рода вещи являются отличительной чертой нестандартных функций: зачастую причина, по которой они не входят в стандарт, заключается в том, что они не очень хорошо сочетаются с функциями других языков, и никто не может придумать разумного предложения для обработки всех возможные случаи.

Другие вопросы по тегам