创建用户定义的类std :: to_string(able)

Hum*_*awi 28 c++ string tostring c++11

我知道Java或C#似乎太多了.但是,将我自己的类作为函数的输入有效是否可行/好/明智std::to_string?例:

class my_class{
public:
std::string give_me_a_string_of_you() const{
    return "I am " + std::to_string(i);
}
int i;
};

void main(){
    my_class my_object;
    std::cout<< std::to_string(my_object);
}
Run Code Online (Sandbox Code Playgroud)

如果没有这样的东西(我认为那样),最好的办法是什么?

Ric*_*ges 21

什么是"最好"的方式是一个开放的问题.

有几种方法.

首先要说的是不允许重载std::to_string自定义类型.我们可能只在命名空间中为自定义类型专门化模板函数和类,而不是模板函数.stdstd::to_string

也就是说,治疗的好方法to_string很像是操作员或实施者swap.即允许参数依赖查找来完成工作.

所以当我们想要将某些东西转换为字符串时,我们可以写:

using std::to_string;
auto s = to_string(x) + " : " + to_string(i);
Run Code Online (Sandbox Code Playgroud)

假设x是名称空间Y中的类型X的对象,并且我是一个int,我们可以定义:

namespace Y {

  std::string to_string(const X& x);

}
Run Code Online (Sandbox Code Playgroud)

现在意味着:

调用to_string(x)实际上选择Y::to_string(const Y::X&),和

调用to_string(i)选择std::to_string(int)

更进一步,你可能希望to_string与operator <<做同样的事情,那么一个可以用另一个来编写:

namespace Y {

  inline std::ostream& operator<<(std::ostream& os, const X& x) { /* implement here */; return os; }

  inline std::string to_string(const X& x) {
    std::ostringstream ss;
    ss << x;
    return ss.str();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果在紧密的循环中执行,则可以*在另一个方面写一个*可能*有性能问题.读者可以决定是否要以必须维护两条代码路径为代价进行优化. (8认同)

Yak*_*ont 18

首先,一些ADL帮助:

namespace notstd {
  namespace adl_helper {
    using std::to_string;

    template<class T>
    std::string as_string( T&& t ) {
      return to_string( std::forward<T>(t) );
    }
  }
  template<class T>
  std::string to_string( T&& t ) {
    return adl_helper::as_string(std::forward<T>(t));
  }
}
Run Code Online (Sandbox Code Playgroud)

notstd::to_string(blah)会做的ADL的查找to_string(blah)std::to_string范围.

然后我们修改你的课程:

class my_class{
public:
  friend std::string to_string(my_class const& self) const{
    return "I am " + notstd::to_string(self.i);
  }
  int i;
};
Run Code Online (Sandbox Code Playgroud)

现在notstd::to_string(my_object)找到了正确的to_string,也是如此notstd::to_string(7).

通过更多工作,我们甚至可以支持.tostring()自动检测和使用的类型方法.

  • @Slava在每次使用`to_string`之前,不需要手动`使用std :: to_string`; 您不必污染命名空间.相反,污染仅在`notstd :: adl_helper`命名空间内完成.你每次只需调用`notstd :: to_string`.我使用`朋友to_string`,但这相当于一个自由函数`to_string`. (8认同)
  • Richard批准此产品或服务. (6认同)
  • 这比理查德的解决方案更好吗? (2认同)

101*_*010 5

您可以to_string在自己的命名空间(例如,foo)中定义自己的命名空间。

namespace foo {
   std::string to_string(my_class const &obj) {
     return obj.string give_me_a_string_of_you();
   }
}
Run Code Online (Sandbox Code Playgroud)

并将其用作:

int main(){
    my_class my_object;
    std::cout<< foo::to_string(my_object);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,您无法定义自己的to_stringin 命名空间版本,std因为根据标准17.6.4.2.1 Namespace std [namespace.std] (Emphasis Mine)

如果 C++ 程序向命名空间 std 或命名空间 std 内的命名空间添加声明或定义,则它的行为是未定义的,除非另有说明。只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且未被明确禁止时,程序才可以将任何标准库模板的模板特化添加到命名空间 std。