Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用户定义的类std::to_可字符串化_C++_String_C++11_Tostring - Fatal编程技术网

C++ 使用户定义的类std::to_可字符串化

C++ 使用户定义的类std::to_可字符串化,c++,string,c++11,tostring,C++,String,C++11,Tostring,我知道这似乎太多Java或C语言了。但是,是否可以/很好/明智地使我自己的类作为函数std::to_string的输入有效? 例如: class my\u class{ 公众: std::string给我一个字符串{ 返回“我是”+std::to_字符串(I); } int i; }; void main(){ 我的类我的对象; std::cout您可能只想重载操作符您可以在自己的名称空间(例如,foo)中定义自己的to_string 并将其用作: int main(){ my_clas

我知道这似乎太多Java或C语言了。但是,是否可以/很好/明智地使我自己的类作为函数
std::to_string
的输入有效? 例如:

class my\u class{
公众:
std::string给我一个字符串{
返回“我是”+std::to_字符串(I);
}
int i;
};
void main(){
我的类我的对象;

std::cout您可能只想重载
操作符您可以在自己的名称空间(例如,
foo
)中定义自己的
to_string

并将其用作:

int main(){
    my_class my_object;
    std::cout<< foo::to_string(my_object);
}
intmain(){
我的类我的对象;

std::cout什么是“最佳”方式是一个悬而未决的问题

有几种方法

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

    template<typename T, typename = std::enable_if_t<std::is_class<T>::value>>
    std::string to_string(const T& t) {
      return t.ToString();
    }
这就是说,处理
到_string
的好方法很像一个操作符或
交换的一个实现。也就是说,允许依赖于参数的查找来完成这项工作

因此,当我们想将某些内容转换为字符串时,我们可以编写:

using std::to_string;
auto s = to_string(x) + " : " + to_string(i);
假设x是命名空间Y中x类型的对象,而我是int,那么我们可以定义:

namespace Y {

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

}
这意味着:

调用
to_string(x)
实际上会选择
Y::to_string(const Y::x&)
,并且

调用
到字符串(i)
选择
std::到字符串(int)


更进一步说,您可能希望\u string执行与运算符相同的操作。您不能将
的新重载添加到\u string
std
命名空间中,但您可以在命名空间中执行此操作:

namespace my {
   using std::to_string;

   std::string to_string(const my_class& o) {
     return o.give_me_a_string_of_you();
   }
}
然后可以对所有类型使用
my::to_string

int main()
{
    my_class my_object;

    std::cout << my::to_string(my_object);
    std::cout << my::to_string(5);
}
intmain()
{
我的类我的对象;

std::cout首先,一些ADL帮助:

namespace notstd {
  namespace adl_helper {
    template<class T>
    std::string as_string( T&& t ) {
      using std::to_string;
      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));
  }
}
现在
notstd::to_string(我的\u对象)
找到正确的
to_string
,就像
notstd::to_string(7)
一样

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


这里有一个替代解决方案。没有什么比这更优雅或太花哨的了,但它是一种替代方法。它假设所有要调用的类都有一个ToString()函数

    template<typename T, typename = std::enable_if_t<std::is_class<T>::value>>
    std::string to_string(const T& t) {
      return t.ToString();
    }
这是一个函数模板,它只处理类类型的对象,并调用ToString()函数

    template<typename T, typename = std::enable_if_t<std::is_class<T>::value>>
    std::string to_string(const T& t) {
      return t.ToString();
    }
模板
标准::字符串到_字符串(常量T&T){
返回t.ToString();
}
也许我们也希望它与std::string一起工作

    template<>
    std::string to_string(const std::string& t) {
      return t;
    }
模板
std::string到_string(const std::string&t){
返回t;
}
这是一个正在使用的代码示例。请注意虚拟名称空间to_s。我想如果您在主函数中使用std::to_字符串,它会影响我们的模板函数名称,因此我们必须像这样间接地引入名称。如果有人知道正确的方法,我将非常感谢您的评论

    #include <cstring>
    #include <iostream>
    #include <string>
    #include <type_traits>


    union U {
      double d;
      const char* cp;
    };

    struct A {
      enum State { kString, kDouble };
      State state;
      U u;

      void Set(const char* cp) {
        u.cp = cp;
        state = kString;
      }

      std::string ToString() const {
        switch (state) {
          case A::kString : return std::string(u.cp); break;
          case A::kDouble : return std::to_string(u.d); break;
          default : return "Invalid State";
        }
      }
    };

    namespace to_s { using std::to_string; };

    int main() {
      using namespace to_s;
      std::string str = "a nice string";
      double d = 1.1;
      A a { A::kDouble, {1.2} };

      std::cout << "str: " << to_string(str) << ", d: " << to_string(d) << std::endl;
      std::cout << "a: " << to_string(a) << std::endl;
      a.Set(str.c_str());
      std::cout << "a: " << to_string(a) << std::endl;
      std::memset(&a, 'i', sizeof(a));
      std::cout << "a: " << to_string(a) << std::endl;
    }
#包括
#包括
#包括
#包括
联合大学{
双d;
常量字符*cp;
};
结构A{
枚举状态{kString,kDouble};
国家;
U U;
无效集(常量字符*cp){
u、 cp=cp;
state=kString;
}
std::string ToString()常量{
开关(状态){
案例A::kString:返回std::string(u.cp);break;
案例A::kDouble:返回std::to_字符串(u.d);中断;
默认值:返回“无效状态”;
}
}
};
命名空间到{using std::to_string;};
int main(){
使用名称空间来_s;
std::string str=“漂亮的字符串”;
双d=1.1;
A{A::kDouble,{1.2};

std::cout这已经有了一个很好的答案,但我想提出一个替代方案,欢迎反馈

如果您对to_字符串函数名不是死板的,您可以实现自己的ToString free函数模板,并对to_字符串支持的类型进行专门化:

template<class T>
std::string ToString(const T& t)
{
    std::ostringstream stream;
    const uint8_t* pointer = &t;
    for(size_t i=0;i<sizeof(T);++i)
    {
        stream << "0x" << std::hex << pointer[i];
    }
    return stream.str();
}

template<> std::string ToString(const int& t) { return std::to_string(t); }
template<> std::string ToString(const long& t) { return std::to_string(t); }
template<> std::string ToString(const long long& t) { return std::to_string(t); }
template<> std::string ToString(const unsigned& t) { return std::to_string(t); }
template<> std::string ToString(const unsigned long& t) { return std::to_string(t); }
template<> std::string ToString(const unsigned long long& t) { return std::to_string(t); }
template<> std::string ToString(const float& t) { return std::to_string(t); }
template<> std::string ToString(const double& t) { return std::to_string(t); }
模板
标准::字符串到字符串(常量T&T)
{
std::奥斯汀溪流;
const uint8_t*指针=&t;

对于(size_t i=0;iRelated也@ShafikYaghmour可能是..但是,那里的解决方案试图重载到_字符串,而不是使类_stringable@Lol4t0不,我的目的不是通过将其转换为string来实现序列化。我不相信有一个重载
std::to_string
可以用于您想要的内容。在C++中,与C/y/java不同,没有任何类继承自所有的基类,因此没有可重写/可重载的<代码> toStReg()/<代码>方法。是的,这是真的。但是,例如,我不能这样做:'相应地编辑了答案,只需将
打印字符串
的行为放入
操作符,谢谢,但是在两个不同的名称空间中有多个字符串不是太容易混淆吗?没有办法使用相同的名称空间吗?@HumamHelfawi没有,不幸的是你不能在
std
中为你的类定义
到字符串
。我认为最后一部分引号的长度(不是粗体)很重要。如果
std::to_string()
是作为模板实现的,您可以为您的用户定义类型专门化
std::to_string()
。但是,它是作为重载函数实现的,所以您不能。很高兴知道
std
库被标记为“不可由外部软件扩展”(一般而言)。这比Richard的解决方案好多少?@Slava它不需要在每次使用
to_string
之前手动
使用std::to_string
;您不必污染名称空间。相反,污染只在
notstd::adl_helper
名称空间内完成。每次只需调用
notstd::to_string
。我使用一个
友元来创建字符串,但这相当于一个免费函数
class my_class{
public:
  friend std::string to_string(my_class const& self) {
    return "I am " + notstd::to_string(self.i);
  }
  int i;
};
    template<typename T, typename = std::enable_if_t<std::is_class<T>::value>>
    std::string to_string(const T& t) {
      return t.ToString();
    }
    template<>
    std::string to_string(const std::string& t) {
      return t;
    }
    #include <cstring>
    #include <iostream>
    #include <string>
    #include <type_traits>


    union U {
      double d;
      const char* cp;
    };

    struct A {
      enum State { kString, kDouble };
      State state;
      U u;

      void Set(const char* cp) {
        u.cp = cp;
        state = kString;
      }

      std::string ToString() const {
        switch (state) {
          case A::kString : return std::string(u.cp); break;
          case A::kDouble : return std::to_string(u.d); break;
          default : return "Invalid State";
        }
      }
    };

    namespace to_s { using std::to_string; };

    int main() {
      using namespace to_s;
      std::string str = "a nice string";
      double d = 1.1;
      A a { A::kDouble, {1.2} };

      std::cout << "str: " << to_string(str) << ", d: " << to_string(d) << std::endl;
      std::cout << "a: " << to_string(a) << std::endl;
      a.Set(str.c_str());
      std::cout << "a: " << to_string(a) << std::endl;
      std::memset(&a, 'i', sizeof(a));
      std::cout << "a: " << to_string(a) << std::endl;
    }
template<class T>
std::string ToString(const T& t)
{
    std::ostringstream stream;
    const uint8_t* pointer = &t;
    for(size_t i=0;i<sizeof(T);++i)
    {
        stream << "0x" << std::hex << pointer[i];
    }
    return stream.str();
}

template<> std::string ToString(const int& t) { return std::to_string(t); }
template<> std::string ToString(const long& t) { return std::to_string(t); }
template<> std::string ToString(const long long& t) { return std::to_string(t); }
template<> std::string ToString(const unsigned& t) { return std::to_string(t); }
template<> std::string ToString(const unsigned long& t) { return std::to_string(t); }
template<> std::string ToString(const unsigned long long& t) { return std::to_string(t); }
template<> std::string ToString(const float& t) { return std::to_string(t); }
template<> std::string ToString(const double& t) { return std::to_string(t); }
template<> std::string ToString(const my_class& t) { return "I am " + std::to_string(t.i); }