Инициализация переменной не компилируется с запятой-оператором

Почему строка, указанная (в main ()) в следующем коде, не компилируется?

#include <iostream>
#include <string>
#include <map>

template< typename _T > struct Inventory : public std::map< _T, int >
{
bool getat(int i, _T &t, int &n)
{
if ((i < 0) || (i >= (int)this->size())) return false;
int c=0;
typename std::map< _T, int >::iterator it = this->begin();

while ((c < i) && (it != this->end())) { c++; it++; }
t = (*it).first;
n = (*it).second;
return true;
}
Inventory &operator=(_T t) { (*this)[t]++; return *this; }
Inventory &operator,(_T t) { return operator=(t); }
};

int main()
{
int i=0, quantity;
std::string item;

//***Fails to compile:***
//Inventory< std::string > inv = "a","b","c","a","c","d","e";

Inventory< std::string > inv;
inv = "a","b","c","a","c","d","e";    //but this is fine
inv = "e","f";

while (i < (int)inv.size())
{
if (inv.getat(i, item, quantity))
std::cout << i << ": " << item << " -> " << quantity << "\n";
i++;
}
return 0;
}

1

Решение

Это называется копией инициализации. Короче говоря, он использует конструктор преобразования, а затем конструктор копирования для создания invне operator = как вы ожидаете.

Inventory< std::string > inv = "a","b","c","a","c","d","e";

неверный синтаксис Что-то вроде Inventory< std::string > inv = "a" будет сначала попытаться создать временный Inventory от "a","b","c","a","c","d","e" а затем использовать этот временный в качестве аргумента конструктора копирования для создания inv, operator = никогда не вызывается в этом случае.

Ваша вторая версия работает, потому что

Inventory< std::string > inv;

вызывает конструктор по умолчанию и

inv = "a","b","c","a","c","d","e";

звонки operator = на уже инициализированном объекте.

2

Другие решения

Вы проблема в том, что в одном случае запятая является пунктуацией (и
перегрузка оператора не применяется), а с другой
оператор. Определение, которое не работает, в основном эквивалентно
из:

Inventory<std::string> inv = "a";
Inventory<std::string> "b";
Inventory<std::string> "c";
//  ...

Из-за этого перегрузка operator, всегда плохой дизайн; когда
запятая является оператором, и когда это не так, слишком тонко.

Обычный способ сделать что-то вроде этого — создать связанный класс
собрать аргументы и передать их в конструктор:

Inventory<std::string> inv = Collector().add("a").add("b")...;

Вы также можете перегрузить оператор и использовать его вместо функции
add, Но я не вижу вероятного оператора (<<, вдохновленный ostream?)
Или вы можете перегрузить конструктор и operator() из
Collector, и писать:

Inventory<std::string> inv = Collector("a")("b")...;

Затем вы будете использовать тот же синтаксис для назначения. (Вы действительно не
хочу что-то, что работает для назначения, а не для копирования
строительство.)

2

По вопросам рекламы [email protected]