Подтвердить что ты не робот

Это использование оператора "," считается плохим?

Я создал класс списка как средство замены вариационных функций в моей программе, используемой для инициализации объектов, которые должны содержать изменяющийся список элементов. Класс 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;
    }
};

Это позволяет мне использовать это в коде, например...

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;
}

Я действительно думаю, что синтаксис намного приятнее, чем если бы я просто открывал обычный stl-контейнер и даже более приятный (и типичный), чем вариативные функции. Однако, поскольку я не видел этот синтаксис, мне интересно, следует ли его избегать, потому что, прежде всего, код должен быть легко понят другими программистами?

EDIT:

В связи с этим вопросом я разместил эту question более целенаправленную задачу по решению реальной проблемы.

4b9b3361

Ответ 1

Почему бы не перегрузить оператор <<, как это делает 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

Ответ 2

Я согласен с тем, что ваш синтаксис выглядит хорошо, как вы его написали. Моя основная проблема с кодом заключается в том, что я ожидаю, что следующее будет тем же самым

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

тогда как на самом деле они совершенно разные.

Это опасно, потому что слишком легко ввести ошибки использования в код. Если кому-то нравится использовать скобки, чтобы добавить дополнительный акцент на группировки (не редкость), то запятая может стать настоящей болью. Например,

//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 

или

new_playlist.queue = (old_playlist.queue, song6); //opps, I edited my old playlist too!

Наверное, вы столкнулись с boost.assign: http://www.boost.org/doc/libs/1_47_0/libs/assign/doc/index.html

Ответ 3

В последнее время изменилось приоритет?

playlist.queue = song1,song2;

Это должно анализироваться как:

(playlist.queue = song1) , song2;

Ваши ',' и '+ =' одинаковы! Было бы лучше семантическое совпадение, если бы ваш оператор запятой должен был создать временный список, вставить левый и правый элементы и вернуть временное. Тогда вы можете написать это следующим образом:

playlist.queue = (song1,song2);

с явным parens. Это дало бы C-программистам шанс на проработку кода.

Ответ 4

Немного проблема в том, что если компилятор не может выбрать вашу перегруженную служебную запятую, он может снова вернуться к использованию встроенного оператора.

В отличие от 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;
}

Ответ 5

Это, вероятно, то, что принадлежит программистам, но здесь мои два цента.

Если вы говорите о коде, который имеет довольно узкий контекст, где пользователи будут использовать его в нескольких местах и ​​что все, то перегрузка оператора ,, вероятно, в порядке. Если вы строите язык, специфичный для домена, который используется в определенном домене, и нигде больше, это, вероятно, отлично.

Проблема возникает, когда вы перегружаете ее для чего-то, что вы ожидаете от пользователя с некоторой частотой.

Перегрузка , означает, что читателю необходимо полностью переосмыслить, как они читают ваш код. Они не могут просто взглянуть на выражение и сразу узнать, что он делает. Вы возитесь с некоторыми из самых основных предположений, которые программисты С++ делают, когда дело доходит до кода сканирования.

Сделайте это на свой страх и риск.

Ответ 6

Мне любопытно, следует ли мне это избегать, потому что, прежде всего, код должен быть легко понят другими программистами.

Если цель состоит в том, чтобы сделать ваш код легким для других программистов на C++, чтобы понять, переопределение операторов, чтобы дать им смысл, который сильно отличается от стандартного С++, не является хорошим началом. Читателям не нужно: a) понимать, как вы реализовали свой контейнер, и b) перекомпилировать их понимание стандартных операторов, чтобы иметь возможность понять ваш код.

Я могу оценить Boost preent для такого рода вещей. Если вы уверены, что большинство людей, которые прочтут ваш код, также будут знакомы с Boost Assign, вашим собственным переопределением оператора, может быть довольно разумным. Тем не менее, я бы предложил следующее предложение @badzeppelin использовать оператор < вместо этого, как и iostreams. Каждый разработчик С++ может рассчитывать на запуск кода:

cout << "Hello world!"`

и ваша операция добавления очень похожа на запись в поток.

Ответ 7

Это плохо на стольких уровнях...

Вы переопределяете list и затеняете std::list. Большой нет-нет. Если вы хотите свой собственный класс списка - сделайте его с другим именем, не затеняйте стандартную библиотеку.

Использование , таким образом не читается. Возвращаемое значение оператора является правильным операндом. Даже если ваш код работает, для внешнего читателя не будет очевидно, почему, и это плохо. Код должен быть читаемым, а не приятным.

Ответ 8

Нет ничего плохого в использовании запятой operator ,, используя специально. Любой оператор оставляет плохой вкус, если его эксплуатируют. В вашем коде я не вижу никаких разумных проблем. Только одно предложение, которое я хотел бы дать, это:

list& operator,(list &add_){  // <--- pass by reference to avoid copies
  *this += add_;  // <--- reuse operator +=
  return *this;
}

Таким образом, вы всегда должны редактировать только operator +=, если хотите изменить логику. Обратите внимание, что мой ответ в перспективе читаемости и обслуживания кода вообще. Я не буду вызывать беспокойство по поводу используемой вами бизнес-логики.