Почему reference_wrapper ведет себя по-разному для встроенных типов?
У меня есть следующее использование std::reference_wrapper
для встроенного типа (double
) и для определенного пользователем типа (std::string
).
Почему они ведут себя по-разному в случае оператора потока?
#include<functional> //reference wrapper
#include<iostream>
void fd(double& d){}
void fs(std::string& s){}
int main(){
double D = 5.;
std::reference_wrapper<double> DR(D);
std::cout << "DR = " << DR << std::endl; //ok
fd(DR); // ok
std::string S = "hello";
std::reference_wrapper<std::string> SR(S);
std::cout << "SR = " << static_cast<std::string&>(SR) << std::endl; // ok
std::cout << "SR = " << SR << std::endl; // error: invalid operands to binary expression ('basic_ostream<char, std::char_traits<char> >' and 'std::reference_wrapper<std::string>')
fs(SR); // ok
}
http://coliru.stacked-crooked.com/a/fc4c614d6b7da690
Почему в первом случае DR преобразуется в двойной и печатается, а во втором - нет? Есть ли работа вокруг?
Хорошо, теперь я вижу, в случае ostream я пытался вызвать шаблонную функцию, которая не разрешена:
#include<functional> //reference wrapper
void double_fun(double const& t){};
template<class C>
void string_fun(std::basic_string<C> const& t){};
int main(){
double D = 5.;
std::reference_wrapper<double> DR(D);
double_fun(DR); //ok
std::string S = "hello";
std::reference_wrapper<std::string> SR(S);
string_fun(SR); // error: no matching function for call to 'string_fun'
string_fun(SR.get()); // ok
string_fun(static_cast<std::string&>(SR)); // ok
string_fun(*&SR); // would be ok if `std::reference_wrapper` was designed/coded differently, see http://stackru.com/a/34144470/225186
}
1 ответ
Для первой части ТС дал вам ответ. То есть оператор<< для basic_string является шаблоном, а вывод аргумента шаблона не просматривает неявные преобразования.
Вы могли бы альтернативно позвонить SR.get()
если вы не хотите явно static_cast
Ваша справочная обертка.
Теперь для второй части, string_fun
принимает в качестве входных аргументов std::basic_string<C>
объекты. Когда вы звоните:
string_fun(SR);
с SR
в качестве входного параметра, который имеет тип std::reference_wrapper<std::string>
естественно вы получаете несоответствие типов.
Что вы можете сделать, это предоставить дополнительную перегрузку:
template<class C>
void string_fun(std::reference_wrapper<std::basic_string<C>> const& t) {
};
Или, если вы хотите более унифицированное лечение, вы можете определить string_fun
взять аргументы шаблона шаблона и разрешить тип с помощью некоторой магии черт типа, как показано ниже:
template<template<typename...> class C, typename T>
void
string_fun(C<T> const &t) {
std::cout <<
static_cast<std::conditional_t<
std::is_same<
std::reference_wrapper<T>, C<T>>::value, T, std::basic_string<T>>>(t) << std::endl;
}