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