给定 std::complex 的 std::vector ,我想将其转换为仅包含复数实部的向量,除以某个常数系数。 现在,我这样做:
std::vector<std::complex<double> > vec;
std::vector<double> realVec;
double norm = 2.0;
...
for (std::vector<std::complex<double> >::iterator it = vec.begin(), itEnd = vec.end(); it != itEnd; ++it)
realVec.push_back((*it).real() / norm);
这当然工作得很好,但我正在寻找一种使用 std::transform 来做同样事情的方法。我试过:
transform(vec.begin(), vec.end(), back_inserter(realVec), tr1::bind(divides<double>(), tr1::bind(&complex<double>::real, tr1::placeholders::_1), norm));
但这行不通。我有这个错误:
erreur: no matching function for call to ‘bind(<unresolved overloaded function type>, std::tr1::_Placeholder<1>&)’|
我不明白为什么会有“未解析的重载函数类型”。
有人可以向我解释一下出了什么问题吗?
不幸的是,你不能这样做,至少不能直接这样做。标准库成员函数的类型(如
complex<double>::real
)未指定,因此实现可能会提供额外的重载,并且那里的函数可能具有带有默认参数的附加参数。
实际上,没有可移植的方法来获取标准库成员函数的地址。
你最好的选择是编写一个辅助函数:
template <typename T>
T get_real(const std::complex<T>& c) { return c.real(); }
并绑定到:
std::tr1::bind(&get_real<double>, std::tr1::placeholders::_1)
std::complex<>::real()
已重载(参见 C++11 [复杂])。
template <typename T>
class complex {
// ...
T real() const; // getter
void real( T ); // setter
// ...
};
当您获取重载函数的地址时,C++ 需要消除歧义。对于你的情况,你必须说:
tr1::bind( static_cast<double(std::complex<double>::*)()const>( &std::complex<double>::real ),
tr1::placeholders::_1 )
是的,这很丑。
对于C++11,你可以这样写
#include <algorithm>
#include <complex>
#include <functional>
#include <iostream>
#include <vector>
int main() {
const std::vector<std::complex<double>> vec = {std::complex<double>(1, 0), std::complex<double>(0, 1)};
std::vector<double> real_vec;
constexpr double norm = 2.0;
std::transform(vec.cbegin(), vec.cend(), std::back_inserter(real_vec), std::bind(std::divides<double>(), std::bind<double (*)(const std::complex<double> &)>(std::real, std::placeholders::_1), norm));
for (const auto &elem : real_vec)
std::cout << elem << '\n';
}
您可以用
using F = double (*)(const std::complex<double> &)
简化并写成 std::bind<F>(std::real, std::placeholders::_1)
。从 C++14 开始,标准运算符模板的模板类型参数通常可以省略,因此您可以编写 std::divides<>()
。