Использование std::transform и tr1 ::bind для преобразования вектора std ::complex

#c #bind #transform #complex-numbers

#c #привязка #преобразование #комплексные числа

Вопрос:

Учитывая std::vector std::complex, я хотел бы преобразовать его в вектор, содержащий только действительную часть комплекса, деленную на некоторый постоянный коэффициент. Прямо сейчас я делаю это:

 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(amp;complex<double>::real, tr1::placeholders::_1), norm));
  

Но это не сработает. У меня эта ошибка:

 erreur: no matching function for call to ‘bind(<unresolved overloaded function type>, std::tr1::_Placeholder<1>amp;)’|
  

Я не понимаю, почему существует «неразрешенный тип перегруженной функции».

Кто-нибудь может объяснить мне, что не так?

Комментарии:

1. Я знаю, что это, вероятно, ересь, но IMO версия, использующая цикл for, намного понятнее.

Ответ №1:

К сожалению, вы не можете этого сделать, по крайней мере, напрямую. Типы функций-членов стандартной библиотеки (например complex<double>::real ) остаются неуказанными, поэтому реализация может создавать дополнительные перегрузки, а функции, которые там есть, могут иметь дополнительные параметры с аргументами по умолчанию.

По сути, не существует переносимого способа получить адрес стандартной библиотечной функции-члена.

Лучше всего было бы написать вспомогательную функцию:

 template <typename T>
T get_real(const std::complex<T>amp; c) { return c.real(); }
  

и привязка к этому:

 std::tr1::bind(amp;get_real<double>, std::tr1::placeholders::_1)
  

Ответ №2:

std::complex<>::real() перегружен (ср. C 11 [complex]).

 template <typename T>
class complex {
    // ...
    T real() const; // getter
    void real( T ); // setter
    // ...
};
  

C требует устранения неоднозначности при использовании адреса перегруженной функции. В вашем случае вы должны сказать:

 tr1::bind( static_cast<double(std::complex<double>::*)()const>( amp;std::complex<double>::real ),
           tr1::placeholders::_1 )
  

Да, это некрасиво.

Комментарии:

1. К сожалению, это не так просто, поскольку реализации разрешено предоставлять дополнительные перегрузки или добавлять дополнительные параметры с аргументами по умолчанию к существующим перегрузкам. 🙁

2. @James: конечно, но OP спросил, почему он получил эту ошибку. Юридический язык хорош, но фраза «вы не можете называть типы функций-членов классов в пространстве имен std» пропускает суть вопроса OP, IMO, которая заключается в устранении неоднозначности, необходимой при получении адреса перегруженной функции.