Ответ 1
stringstream ss << "Number of people is " << numPeople;
Почему я не могу присвоить значение
stringstream
в то же время, я объявляю его?
Это похоже на надежду, что это сработает:
int x + 3 + 9;
Проблема
Только С++ позволяет предоставить значение конструктору при создании объекта, а конструктор принимает список выражений, разделенных запятыми. Для удобства нотация Type variable = value;
позволяет вызвать Type variable(value);
, но работает только для одного значения.
Для int
вы можете легко исправить код:
int x = 3 + 9;
... и он работает, потому что сначала можно оценить значение "3 + 9", чтобы получить нормальное значение для хранения в x
. Поведение компилятора для оператора +
на int
делает то, что мы хотим. Производит int результат. Но если вы попробуете это для stringstream
...
stringstream ss = "Number of people is " << numPeople; // BROKEN
... это не сработает, потому что "Number of people is " << numPeople
является незаконным - вы получите сообщение об ошибке "error C2296: '<<' : illegal, left operand has type 'const char [20]'
" - это не даст полезного значения для конструктора stringstream
. Проблема заключается в том, что компилятор все еще пытается применить оператор поразрядного сдвига, что имеет смысл только для чисел, так как перегрузки для <<
, которые мы хотели бы применить, требуют левого аргумента типа ostream&
. С++ требует, чтобы значение, оцениваемое справа от =
, оценивалось независимо от назначения, которое в конечном итоге было выполнено с полученным значением.
Решение
Это немного проблема с курицей и яйцом, потому что вам нужно объединить нужные значения в stringstream
, чтобы вызывать конструктор stringstream
, но для этого вам нужно.. a stringstream
. Фактически вы можете снять это с помощью временного stringstream
:
static_cast<std::ostringstream&&>(std::ostringstream() << "Number of people is " << numPeople)
К сожалению, приведение роли происходит потому, что перегрузка operator<<
обрабатывает stringstream
через ссылки на их базовый класс ostream
, возвращая ostream&
, поэтому вам нужно вручную вернуться к типу stringstream
, так что вы может затем вызвать конструктор перемещения std::stringstream
...
Полная однострочная конструкция тогда...
std::stringstream ss(static_cast<std::ostringstream&&>(std::ostringstream() << "Number of people is " << numPeople));
... но это слишком ужасно, чтобы созерцать.
Создание решения (возможно) менее отвратительного
В зависимости от вашей чувствительности вы можете почувствовать, что макрос помогает или хуже...
#define OSS(VALUES) \
static_cast<std::ostringstream&&>(std::ostringstream() << VALUES)
std::stringstream ss(OSS("Number of people is " << numPeople));
FWIW, вы также можете использовать макрос для создания строк...
std::string s(OSS("Number of people is " << numPeople).str());
Лучшая практика (возможно)
Просто создайте stringstream
- опционально предоставляя одиночный string
конструктору, а затем используйте operator<<
во втором выражении:
std::stringstream ss;
ss << "Number of people is " << numPeople;
Это гораздо легче читать. С построением перемещения, после оптимизации, вероятно, нет причин для оптимизации двух операторов.
Альтернативный
С++ 11 внесли to_string()
перегрузки, которые удобны, если у вас есть целое значение или два, чтобы совместить с или в string
:
std::string s = "Number of people is " + std::to_string(numPeople);
Это может быть неэффективным, хотя (если хотите) проверьте возможности оптимизации вашего компилятора (ы): каждый std::to_string()
, вероятно, динамически выделяет буфер для независимого экземпляра std::string
, тогда отдельные конкатенации могут включать дополнительное копирование текст и исходные динамически распределенные буферы, возможно, потребуется увеличить.
Это было хуже в С++ 03
С++ 03 не хватало конструкторов перемещения, поэтому необходимо было использовать функцию std::ostringstream::str()
на временном, чтобы получить std::string
, с помощью которого можно создать названный stringsteam
...
stringstream ss(static_cast<std::ostringstream&>(std::ostringstream() << "Number of people is " << numPeople).str());
С помощью этого кода С++ 03 существует вероятность дублирования распределений динамической памяти и копии содержимого, поэтому лучше всего было бы выполнить построение с последующим потоком.