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

时间:2015-02-20 08:49:32

标签: c++ c++11 complex-numbers user-defined-literals

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

typeid(complex<double>(0.0,1.0)) != typeid(1.0i)
  1. 我在这里弄错了吗?
  2. 这是编译错误还是预期的标准行为?
  3. 如果是预期的标准行为:背后的理由是什么?
  4. 添加缺少的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 个答案:

答案 0 :(得分:20)

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

gcc extension for a built-in literal suffix i生成 C99复数。这些是不同的内置类型,如_Complex double,而不是&#34;用户定义的&#34; C ++中使用的类(模板特化)std::complex<double>

在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>