这种","运算符的使用是否被视为不良形式?

Sky*_*leh 28 c++ operator-overloading comma

我已经创建了一个列表类作为替换我的程序中的可变参数函数的方法,该程序用于初始化需要包含更改的元素列表的对象.list类有一个我非常喜欢的用法语法.但是我之前没有看过它,所以我想知道我是不是因为这个事实而不应该使用它?列表类的基本实现看起来像这样......

#include <list>
#include <iostream>
template<typename T>
struct list
{
    std::list<T> items;
    list(const list&ref):items(ref.items){}
    list(){}
    list(T var){items.push_back(var);}
    list& operator,(list add_){
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
    list& operator=(list add_){
        items.clear();
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
    list& operator+=(list add_){
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
};
Run Code Online (Sandbox Code Playgroud)

这允许我在代码中使用它,如此...

struct music{
//...
};
struct music_playlist{
    list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
    music_playlist playlist;
    music song1;
    music song2;
    music song3;
    music song4;
    playlist.queue = song1,song2; // The queue now contains song1 and song2
    playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
    playlist.queue = song2; //the queue now only contains song2
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我真的认为语法比我刚刚暴露一个常规的stl容器,甚至比可变参数函数更好(和类型安全)更好.但是,由于我没有看到使用这种语法,我很好奇是否应该避免使用它,因为最重要的是代码应该容易被其他程序员理解?

编辑:

结合这个问题,我发布了这个问题更有针对性地解决了实际问题.

rgn*_*ngl 40

为什么不像<<QList那样重载运算符?然后使用它像:

playlist.queue << song1 << song2; // The queue now contains song1 and song2
playlist.queue << song1 << song3 << song4; //The queue now contains two song1s and song2-4
Run Code Online (Sandbox Code Playgroud)

  • +1:即使这对眼睛来说更加丑陋(我认为它是这样),它至少具有移位运算符重载的其他用法的先例,意味着"将某个对象置于某个地方",这是以iostream开始的.因此,我认为这是惯用的,并且不太可能让新的代码混淆而不是重载逗号运算符. (18认同)
  • @RTS:窃取另一个iostreams的想法,操纵者:`playlist.queue << music_playlist :: clear << song2;` (7认同)
  • @RTS:我不会.只需分配一个空列表,或调用`clear`函数或类似的东西,然后重新开始插入. (5认同)

Tom*_*Tom 20

我同意你写的语法很好看.
我对代码的主要困难是我希望以下内容是相同的

playlist.queue = song1,song2;
playlist.queue = (song1,song2);  //more of c-style, as @Iuser notes.
Run Code Online (Sandbox Code Playgroud)

事实上它们完全不同.

这很危险,因为它太容易在代码中引入使用错误.如果有人喜欢使用括号来为分组添加额外的重点(并非罕见),那么逗号可能会成为一个真正的痛苦.例如,

//lets combine differnt playlists
new_playlist.queue =    song1        //the first playlist
                      ,(song3,song4) //the second playlist //opps, I didn't add song 3!
                      , song5;        //the third 
Run Code Online (Sandbox Code Playgroud)

要么

new_playlist.queue = (old_playlist.queue, song6); //opps, I edited my old playlist too!
Run Code Online (Sandbox Code Playgroud)

你是否真的遇到过boost.assign:http://www.boost.org/doc/libs/1_47_0/libs/assign/doc/index.html


lus*_*oog 11

最近是否改变了优先顺序?

playlist.queue = song1,song2;
Run Code Online (Sandbox Code Playgroud)

这应解析为:

(playlist.queue = song1) , song2;
Run Code Online (Sandbox Code Playgroud)

你的','和'+ ='是一样的!如果您的逗号运算符要创建临时列表,插入左侧和右侧项并返回临时项,那将是更好的语义匹配.然后你就可以这样写;

playlist.queue = (song1,song2);
Run Code Online (Sandbox Code Playgroud)

明确的parens.这将使C程序员有机会阅读代码.


Unc*_*ens 7

有点问题是,如果编译器无法选择重载的运算符逗号,它可以使用内置运算符.

相反,使用Boost.Assign混合类型会产生编译错误.

#include <boost/assign.hpp>

int main()
{
    int one = 1;
    const char* two = "2";
    list<int> li;
    li = one, two;

    using namespace boost::assign;
    std::list<int> li2;
    li2 += one, two;
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*las 5

这可能属于程序员,但这是我的两分钱.

如果你在谈论具有相当狭窄的上下文的代码,用户将在几个地方使用它,那就是全部,那么重载,运算符可能就行了.如果您正在构建特定域中使用的特定于域的语言,那么它可能没什么问题.

当您为某些预期用户以某种频率使用的内容超载时会出现问题.

重载,意味着读者需要完全重新解释他们如何阅读您的代码.他们不仅可以查看表达式,还可以立即知道它的作用.你正在搞乱C++程序员在扫描代码时所做的一些最基本的假设.

这样做是你自己的危险.


Cal*_*leb 5

我很好奇是否应该避免它,因为最重要的是代码应该很容易被其他程序员理解

如果我们的目标是让您的代码易于其他C++程序员理解,那么重写操作符以赋予它们与标准C++非常不同的含义并不是一个好的开始.读者不应该a)了解您如何实现容器,以及b)重新校准他们对标准操作符的理解,以便能够理解您的代码.

我可以理解这种事情的Boost先例.如果您非常确定大多数将阅读您的代码的人也熟悉Boost Assign,那么您自己的操作符覆盖可能非常合理.不过,我建议遵循@ badzeppelin建议使用operator <<,就像iostreams一样.每个C++开发人员都可以依赖于以下代码:

cout << "Hello world!"`
Run Code Online (Sandbox Code Playgroud)

并且您的追加操作与写入流非常相似.