【问题标题】:typeid(complex<double>(0.0,1.0)) != typeid(1.0i)typeid(complex<double>(0.0,1.0)) != typeid(1.0i)
【发布时间】:2015-04-21 21:19:59
【问题描述】:

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

typeid(complex<double>(0.0,1.0)) != typeid(1.0i)
  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;
}

编译说明:

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

输出:

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

有趣的是,文字甚至看起来都不是一个适当的虚数。 (我确定我忽略了一些东西......)

【问题讨论】:

  • 你有没有机会把它放在一个实际编译的源列表中?我认为你正在使用std::complex&lt;double&gt;,它不同于_Complex,它是虚数常量的gnu-extension,但是没有MCVE很难说what你'真的在做。
  • 感谢您的更新。是的,它们是不同的类型。一个来自标准库,另一个来自编译器扩展。
  • Cannot reproduce the problem in C++14 @WhozCraig i 是(也是?)C++ 14 中的文字后缀。 C++11模式下,gcc大概使用this extension
  • @WhozCraig clang++ 在 c++11 模式下接受程序 带有 gnu++11 扩展 可能是一个错误 o.O
  • @dyp 当我自己看到它时,我不得不加倍考虑。我的 mac OS X clang 3.5 参考也是如此,但至少会给出一个警告,让您知道它是一个 gnu 扩展。

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


【解决方案1】:

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

有一个gcc extension for a built-in literal suffix i 产生C99 复数。这些是不同的内置类型,例如 _Complex double,与 C++ 中使用的“用户定义”类(模板特化)std::complex&lt;double&gt; 不同。

在 C++14 中,C++ 现在有一个 用户定义 文字后缀 i 用于复数。即,std::literals::complex_literals 内联命名空间内的函数 complex&lt;double&gt; operator"" i(long double)

这两个文字后缀在竞争:

  • 在 C++11 模式下,只有内置扩展是可能的,但它一个扩展。因此,gcc 只允许在-std=gnu++11 模式下使用它,甚至会发出警告。奇怪的是,即使在-std=c++11 模式下,clang 也允许它。

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

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

根据选择的文字后缀,您可以获得内置类型 _Complex double 或一些 std::complex&lt;double&gt;

【讨论】:

  • 出色的答案。我一直忘记用户定义的文字属于保护伞。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 2013-04-22
  • 2010-12-31
  • 2020-08-28
  • 1970-01-01
相关资源
最近更新 更多