为std::string重载C++运算符<<

3
我现在看到另一个天真的C++代码,使用sprintf将C内置函数附加到字符数组中,我想够了。
我可以提供简单、轻量级、追加和非格式化函数给std::string,但由于它将被检入团队的公共代码,我希望它是完美的,所以我需要一些关于这个特性接口的建议(即不是实际实现方面的建议)。
以下可能是可能的(我没有测试过,这只是一种预感):
1. 重载"+="运算符(可能在std或全局命名空间之外) 2. 重载"<< "运算符(同样,在另一个命名空间中) 3. 提供非运算符非成员函数(我猜,同样在另一个命名空间中) 4. 我没有看到的另一个简单解决方案?
每种解决方案的优缺点是什么(我更喜欢“+=”,甚至是“<<”)?

笔记

  • 关键不在于格式。如果有人需要格式化,C++流是很好的选择。我只想要简单、轻量级的一句话/函数调用追加。
  • 使用另一个命名空间是因为我们没有权限向std命名空间添加代码,而且我不想污染全局命名空间,所以,是的,我猜用户必须添加using namespace SomeNamespace;就像对于<utility>rel_ops命名空间一样)
  • 我正在使用std::string它本身不能处理除了自身、charchar *之外的其他类型。 我想扩展它来处理其他简单类型。
  • 使用stringstream在代码方面太重(声明流,追加,然后检索.str()将其放入字符串中等等),我最不想要的是一个语法糖式的内联函数在每次调用时实例化一个stringstream)。正如下面的示例中所示,stringstream解决方案太冗长了

.

// sprintf-like code with a char[] buffer:
sprintf(buffer, "%d", myDouble) ;

// stream-like code with a std::string buffer:
std::stringstream str ;
str << myDouble ;
buffer = str.str() ;

// example of desired code with a std::string buffer:
buffer += myDouble ;

4
为什么不直接重构代码使用std::string?它具备了你所需的一切,而且更加强大。 - Björn Pollex
@Björn Pollex:不完全正确。如果我想要附加除了std::stringcharchar *之外的其他类型,我需要使用std::stringstream。我添加了一条注释以澄清这一点。 - paercebal
@Cody Gray:std::string。我添加了一个注释来澄清。 - paercebal
所以,你的意思是想创建一个 std::string & operator+=(std::string &, int) 吗?这听起来不是一个好主意。你考虑过使用 boost::lexical_cast 吗?虽然我猜它内部使用了 stringstream,所以可能不符合你的要求。 - Björn Pollex
顺便提一下,gnu autosprintf(我相信是gettext的一部分)-http://www.rootr.net/man/info/autosprintf-可能会对您有用,或者给您灵感。 - Michael Krelin - hacker
显示剩余5条评论
4个回答

3

不是一个好的解决方案。请看我的注释,为什么stringstream过于冗长,对于我想要的东西没有任何用处。我不是要重新发明轮子。我只是想添加轻量级的语法糖。 - paercebal
1
好的,你是老板 :) 我只是不明白为什么你认为重新实现如此复杂的功能以节省2行代码(创建oss对象和.str()调用)是个好主意。好吧,想象一下你写了一些简单的东西:你可以将字符串、整数和双精度浮点数连接到现有字符串中。然后你的一个同事写了这个:sprintf(buffer, "%08llu\t%08X", x, y);。你真的想花费你的生命一遍又一遍地添加新的格式化特性吗?我敢打赌,在几个月内,你最终会得到与ostringstream非常相似的东西... - kol
1
上个月我用C#重新实现了Excel的字符串、数字(包括普通分数)和日期时间格式化功能。我的雇主本可以使用现有的.NET格式化功能,但他想要与Excel完全匹配。这是一个你无法避免“重新发明轮子”的情况。你的情况不同:你可以使用现有的功能,即ostringstream,你不必复制已经被其他人创建和优化的功能。 - kol
我并不打算提供一个全面的、适用于所有可能情况的解决方案。只是简单的字符串拼接而已,没有格式化。所以sprintf(buffer, "%08llu\t%08X", x, y)要么保持原样,要么被stringstream等效替代。现在我想要的是,在简单的情况下,避免使用C风格的字符数组和sprintf,仅仅因为编码者没有弄清楚如何使用stringstream或者不想使用它,因为对于它应该做的事情来说,多出两行无用的代码太多了。 - paercebal
无论如何,你甚至不知道实现会是什么样子。也许我会在内部使用stringstream。我的问题是关于接口,而不是实际的实现。你提供了一个我没有问到的问题的建议和解决方案。 - paercebal

3
  1. What about boost::format ? Then you can write:

    std::string first("world");
    std::string s = (boost::format("hello %1%") % first).str();
    
  2. Or create a wrapper class which you can use like so:

    int i(2);
    std::string s = (Format() + "Hello " + first + " " + i).str();
    

    And Format() something like (without boost) :

    class Format
    {
        public:
            template <typename T>
            Format &operator+(const T& v) {
                m_sstr << v; 
                return *this;
            };
            const std::string &str() const { return m_sstr.str(); };
        private:
            std::stringstream m_sstr;
    };
    

现在,我更多的想法是像http://www.fastformat.org/这样的东西。由于历史原因(不要问...),Boost对我们的应用程序并不真正可用,我甚至怀疑我能否推动fastformat的使用,这就是为什么一个轻量级函数将是一个很好的妥协的原因。 - paercebal
@paercebal:我从第二个选项中删除了boost,也许这对你有用? - rve
我喜欢第二种解决方案的实现方式,它的界面很有趣。我猜stringstream甚至可以成为私有成员变量,每次调用“append”运算符时都可以重复使用。 - paercebal
@paercebal:当然,那样会更好,我会编辑我的回答。 - rve

3
C++11提供了一组重载的std::to_string函数。
示例原型:
std::string to_string( int value );

它们可以被用户重写(在C++11中)。现在你需要自己的命名空间。

您可以为所选类型实现自己的集合。这将使代码具有未来的可扩展性。

您将使用以下代码:

std::string s;
s+=std::to_string(1);

C++11的解决方案加1分。虽然我不喜欢创建字符串的事实,但是在阅读您的帖子时,我学到了一些关于C++11的知识。谢谢...为了记录,我正在考虑类似于std::string&append(std :: string&p_string,const T&p_value);的东西。 - paercebal
我认为考虑到你的限制,你的建议非常优秀。 - mirk

0
boost::lexical_cast 提供了一个潜在的模型 - 编写一个函数,可以处理你需要的任何数据类型,将它们转换为适合你目的的字符串格式(你可以尽可能地优化它),并将它们返回以便与 operator+(string, string) 一起使用。
根据你的喜好,使用正常重载或模板特化来针对每种类型专门化该函数。lexical_cast 使用模板,因此它可以通过定义的任何流操作符处理绝对任何东西,但是你的用例远比这窄得多,因此你肯定可以从中获得更多的性能。

不好。即使使用专门化,boost::lexical_cast 仍会返回一个临时的 std::string,而我想避免这种情况(我需要“追加”,而不是“复制”)。 - paercebal
所以,只需将其制作成一个函数,该函数接受要附加到的字符串和要附加的内容。然后开始重载运算符+=看起来非常不错。 - Matthew Walton
是的,这正是我在提问之前所考虑的。这就是为什么我请求建议,询问使用函数还是运算符重载(+=<<)的优缺点。 - paercebal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接