(C ++) Внутренняя ошибка компилятора при инициализации с помощью фигурных скобок и значений - PullRequest
0 голосов
/ 13 января 2019

Я столкнулся со странной проблемой, которая, кажется, зависит от синтаксиса инициализации, который я использую. Компилятор сообщает только о внутренней ошибке, и только когда я использую список инициализатора с элементами rvalue.

Сначала я создал тип для обозначения значения в виде угла.

math.hpp:

// ...
template<class S = float>
struct Angle { S value = 0, cosine = cos(value), sine = sin(value); };
// ...

Далее кватернион (математический объект, не очень важный) с различными конструкторами для регулярных значений и формы осевого угла.

quaternion.hpp:

// ...
template<class S = float>
struct Quaternion {
    S w, x, y, z;
    // ...
    Quaternion(S && w = 0, S && x = 0, S && y = 0, S && z = 0):
        w(std::move(w)), x(std::move(x)), y(std::move(y)), z(std::move(z)) {}
    Quaternion(S const& w, S const& x, S const& y, S const& z):
        w(w), x(x), y(y), z(z) {}
    Quaternion(Angle<S> const& t = {0}, S const& x = 0, S const& y = 0, S const& z = 0):
        w(t.cosine), x(t.sine*x), y(t.sine*y), z(t.sine*z) {}
    template<class T> Quaternion(Quaternion<T> const& q):
        w(q.w), x(q.x), y(q.y), z(q.z) {}
    template<class T> Quaternion(Quaternion<T> && q):
        w(std::move(q.w)), x(std::move(q.x)), y(std::move(q.y)), z(std::move(q.z)) {}
    virtual ~Quaternion(void) {}
};
// ...

Вот как это выглядит при использовании - все методы инициализации как углов, так и кватернионов выглядят допустимыми, но, как я описал ранее, только одна комбинация методов вызывает эту внутреннюю ошибку компилятора.

quaternion.cpp:

typedef float T;
T theta = M_PI/2;
Angle<T> a { theta }, b = { theta };
Quaternion<T> q1 = 1, q2 = {2}, q3 = {3, 4, 5, 6},
    qval1(Angle<T>{theta}, 1, 0, 0),
    // qval2 = {Angle<T>{theta}, 1, 0, 0},
    // internal compiler error: in replace_placeholders_r, at cp/tree.c:2804
    qref1(a, 1, 0, 0),
    qref2 = {a, 1, 0, 0};

Я компилирую это как C ++ 14 с gcc версии 7.3.0. Что является причиной ошибки? Должен ли я сообщить об этом? Есть ли обходной путь, или я должен просто избегать этого метода?

1 Ответ

0 голосов
/ 13 января 2019

Внутренние ошибки компилятора всегда являются ошибками в компиляторе. Лучше избегать областей вокруг них, даже если это «действительно должно работать в теории».

Мой опыт показывает, что расширенные методы инициализации обычно являются слабым полем в компиляторах. Тестовые наборы, кажется, избегают этого. У меня были аналогичные проблемы 19 лет назад с gcc, использующим C и инициализацию именованных полей, что приводило к внутренним ошибкам компилятора в некоторых случаях.

Попробуйте более новую версию компилятора (например, gcc 8).

Обходной путь, если вам нужен переносимый код: добавьте конструктор по умолчанию и поместите весь код инициализации в конструктор. Используйте инициализацию только для таких тривиальных вещей, как простые постоянные значения (не вычисляются).

...