为什么reference_wrapper对内置类型的行为有所不同?

alf*_*lfC 5 iostream built-in user-defined-types c++11 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 
}
Run Code Online (Sandbox Code Playgroud)

http://coliru.stacked-crooked.com/a/fc4c614d6b7da690

为什么在第一种情况下DR被转换为double并打印,而在第二种情况下它不是?有工作吗?


好的,我现在看到,在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://stackoverflow.com/a/34144470/225186
}
Run Code Online (Sandbox Code Playgroud)

101*_*010 2

第一部分TC给了你答案。也就是说,basic_string 的operator<< 是模板化的,并且模板参数推导不会通过隐式转换进行查找。

SR.get()如果您不想显式地调用static_cast参考包装器,您也可以调用。

现在对于第二部分,string_funstd::basic_string<C>对象作为输入参数。你打电话时:

string_fun(SR);
Run Code Online (Sandbox Code Playgroud)

SR输入参数的类型为 时std::reference_wrapper<std::string>,自然会出现类型不匹配的情况。

你可以做的是提供额外的重载:

template<class C>
void string_fun(std::reference_wrapper<std::basic_string<C>> const& t) {

};
Run Code Online (Sandbox Code Playgroud)

现场演示

或者,如果您想要更统一的处理,您可以定义您的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;
}
Run Code Online (Sandbox Code Playgroud)

现场演示