以下代码
#include <vector>
#include <complex>
#include <algorithm>
template<class K>
inline void conjVec(int m, K* const in) {
static_assert(std::is_same<K, double>::value || std::is_same<K, std::complex<double>>::value, "");
if(!std::is_same<typename std::remove_pointer<K>::type, double>::value)
#ifndef OK
std::for_each(in, in + m, [](K& z) { z = std::conj(z); });
#else
std::for_each(reinterpret_cast<std::complex<double>*>(in), reinterpret_cast<std::complex<double>*>(in) + m, [](std::complex<double>& z) { z = std::conj(z); });
#endif
}
int main(int argc, char* argv[]) {
std::vector<double> nums;
nums.emplace_back(1.0);
conjVec(nums.size(), nums.data());
return 0;
}
使用
在Linux上编译正常和Mac OS X上的
但不是
除非定义了宏OK
。我不知道哪些是错误的编译器,有人能告诉我吗?感谢。
PS:这是错误
10:48: error: assigning to 'double' from incompatible type 'complex<double>'
std::for_each(in, in + m, [](K& z) { z = std::conj(z); });
答案 0 :(得分:5)
不同之处在于,在Linux上,您使用的是libstdc ++和glibc,而在MacOS上,您使用的是libc ++以及CRT MacOS使用的任何内容。
MacOS版本是正确的。 (此外,您的解决方法完全被破坏并且非常危险。)
这就是我认为发生的事情。
环境中有多个conj
重载。 C ++ 98引入了一个模板,它采用std::complex<F>
并返回相同的类型。由于此模板需要推导出F
,因此在使用简单的浮点数调用conj
时它不起作用,因此C ++ 11添加了conj
的重载,其中{{1} },float
和double
,并返回相应的long double
实例。
然后是来自C99库std::complex
的全局函数,它接受C99 ::conj
并返回相同的内容。
double complex
重载。不调用conj
的C ++版本。但是,似乎conj
以某种方式进入::conj
命名空间,并被调用。您传递的std
通过添加零虚部隐式转换为double
。 double complex
否定零。结果conj
通过丢弃虚构组件隐式转换回double complex
。 (是的,这是C99中的隐式转换。不,我不知道他们在想什么。)结果可以分配给double
。
libc ++提供了新的重载。选择z
的人。它返回double
。此类没有隐式转换为std::complex<double>
,因此对double
的分配会给您一个错误。
最重要的是:你的代码完全没有意义。 z
不是vector<double>
,不应视为一个。在vector<complex<double>>
上拨打conj
没有意义。要么它不编译,要么它是无操作。 (libc ++的double
实际上是通过简单地构造一个虚部为零的conj(double)
来实现的。)然而,complex<double>
编译错误非常可怕。
答案 1 :(得分:3)
Sebastian Redl的回答解释了为什么你的代码没有用libc ++编译,而是用libstdc ++编译。 if
不是某些语言中存在的static if
;即使if
分支中的代码100%死亡,它仍然必须是有效的代码。
无论如何,这对我来说感觉就像是一个巨大的不必要的复杂性。并非一切都必须是模板。特别是当你的模板只能用于两种类型时,当与这两种类型中的一种一起使用时,它就是一种无操作。
比较
template<class K>
inline void conjVec(int m, K* const in) {
static_assert(std::is_same<K, double>::value || std::is_same<K, std::complex<double>>::value, "");
if(!std::is_same<K, double>::value)
std::for_each(reinterpret_cast<std::complex<double>*>(in), reinterpret_cast<std::complex<double>*>(in) + m, [](std::complex<double>& z) { z = std::conj(z); });
}
使用:
inline void conjVec(int m, double* const in) {}
inline void conjVec(int m, std::complex<double>* const in) {
std::for_each(in, in + m, [](std::complex<double>& z) { z = std::conj(z); });
}
我知道我更喜欢哪一个。