Typeid (сложный <double> (0.0,1.0))!= typeid (1.0i)

Используя gcc 4.9, я обнаружил, что типы, сгенерированные с литералом типа для сложных чисел, не совпадают с типами, созданными обычными способами, то есть:

typeid(complex<double>(0.0,1.0)) != typeid(1.0i)
  • Я делаю ошибку здесь?
  • Является ли это ошибкой компилятора или стандартным поведением?
  • Если предполагаемое стандартное поведение: в чем причина?

Добавление отсутствующего MCVE

#include <complex>
using std::complex;
using namespace std::literals::complex_literals;

#include <iostream>
using std::cout;
using std::endl;

#include <typeinfo>

int main(int argc, char* argv[]) {
    if (typeid(complex<double>(0.0, 1.0)) == typeid(1.0i))
        cout << "types are same as expected" << endl;
    else
        cout << "types are unexpectedly not the same" << endl;

    cout << 1.0i*1.0i << endl;
    cout << complex<double>(0.0, 1.0)*complex<double>(0.0, 1.0) << endl;
}

Инструкции по компиляции:

g++ -std=gnu++14 complex.cpp -o complex.exe

Вывод:

types are unexpectedly not the same
1
(-1,0)

Интересно, что литерал даже не кажется правильным мнимым числом. (Я уверен, что я что-то пропускаю...)

Ответ 1

Поведение программы зависит от стандартного режима языка gcc:

Существует расширение gcc для встроенного литерального суффикса i, который создает комплексные числа C99. Это разные встроенные типы, такие как _Complex double, в отличие от "определяемого пользователем" класса (специализация шаблона) std::complex<double>, используемого в С++.

В С++ 14, С++ теперь имеет определяемый пользователем буквенный суффикс i для сложных чисел. То есть, функция complex<double> operator"" i(long double) внутри встроенного пространства имен std::literals::complex_literals.

Эти два буквальных суффикса конкурируют:

  • В режиме С++ 11 возможно только встроенное расширение, но это расширение. Следовательно, gcc разрешает его только в режиме -std=gnu++11 и даже предупреждает об этом. Как ни странно, clang позволяет даже в режиме -std=c++11.

  • В строгом режиме С++ 14 (-std=c++14 или -std=c++1y) встроенное расширение необходимо отключить, чтобы устранить неоднозначность (насколько я могу судить), следовательно, gcc и clang выбирают определяемый пользователем буквенный суффикс.

  • В режиме gnu-extension-С++ 14 -std=gnu++14 gcc выбирает встроенный суффикс (для обратной совместимости?), тогда как clang выбирает определяемый пользователем суффикс. Это выглядит странно, и я предлагаю искать или регистрировать отчеты об ошибках здесь.

В зависимости от того, какой буквенный суффикс выбран, вы либо получаете встроенный тип _Complex double, либо некоторый std::complex<double>.