typeid(complex <double>(0.0,1.0))!= typeid(1.0i)

rol*_*and 12 c++ complex-numbers user-defined-literals c++11

使用gcc 4.9我发现用复数形式的文字生成的类型与通过常规方法创建的类型不同,即:

typeid(complex<double>(0.0,1.0)) != typeid(1.0i)
Run Code Online (Sandbox Code Playgroud)
  1. 我在这里弄错了吗?
  2. 这是编译器错误还是预期的标准行为?
  3. 如果是预期的标准行为:背后的理由是什么?

添加缺少的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;
}
Run Code Online (Sandbox Code Playgroud)

编译说明:

g++ -std=gnu++14 complex.cpp -o complex.exe
Run Code Online (Sandbox Code Playgroud)

输出:

types are unexpectedly not the same
1
(-1,0)
Run Code Online (Sandbox Code Playgroud)

有趣的是,文字似乎甚至不是一个合适的想象数字.(我确信我忽略了一些......)

dyp*_*dyp 20

程序的行为取决于gcc 的语言标准模式:

内置文字后缀有一个gcc扩展i,可生成C99复数.这些是不同的内置类型_Complex double,而不是std::complex<double>C++中使用的"用户定义"类(模板特化).

在C++ 14中,C++现在具有用于复数的用户定义的文字后缀i.也就是说,complex<double> operator"" i(long double)std::literals::complex_literals联命名空间中的一个函数.

这两个字面后缀是竞争的:

  • 在C++ 11模式下,只能使用内置扩展,但它扩展.因此,gcc只允许它在-std=gnu++11模式中,甚至会警告你.奇怪的是,clang甚至可以在-std=c++11模式中使用它.

  • 严格的 C++ 14模式(-std=c++14-std=c++1y)中,必须禁用内置扩展以消除歧义(据我所知),因此gcc和clang都选择用户定义的文字后缀.

  • 在gnu-extension-C++ 14模式中-std=gnu++14,gcc选择内置后缀(为了向后兼容?),而clang选择用户定义的后缀.这看起来很奇怪,我建议在这里寻找或归档错误报告.

根据选择的文字后缀,您可以获得内置类型_Complex double或其他类型std::complex<double>.