У меня есть класс, давайте назовем это Sample
с переменными аргументами шаблона. Этот класс содержит функцию run(Args... args)
, Этот класс также реализует оператор потока, который вызывает эту функцию.
Класс выглядит так:
template<typename ...Args>
class Sample
{
void run(Args... args)
{
// do something
}
Sample& operator<<(const tuple<Args...>& args)
{
run(unpack_somehow(args)...);
return *this;
}
};
Теперь я хочу использовать потоковый оператор для объединения нескольких вызовов, передавая аргументы через инициализацию кортежей кортежей:
void main()
{
Sample<int, string, int> s;
// doesn't work :(
s << {1, "msg", 2} << {1, "msg", 2};
}
Я знаю, я мог бы просто написать make_tuple(1, "msg", 2)
и это будет работать, но я ищу решение, которое не требует дополнительных вызовов функций, таких как make_tuple
,
Есть ли способ реализовать такую функцию, чтобы я мог передавать аргументы в фигурных скобках (или, возможно, через запятую, перегружая оператор запятой)?
Когда вы используете линию s << {1, "msg", 2} << {1, "msg", 2};
он не предоставляет компилятору C ++ достаточно информации, чтобы понять, что вы подразумеваете под этими списками инициализаторов.
Если вы не дадите подсказку компилятору (используйте make_tuple
или передать фактический tuple
переменная) он не будет знать, что вы имеете в виду, и не сможет вызвать соответствующий operator<<()
,
Похоже, вам не повезло. Это невозможно сделать так, как ваш вопрос опубликован.
Списки инициализаторов не включены на стороне оператора.
Они не включены с правой стороны, потому что они не включены с левой стороны, и они не включены с левой стороны, потому что это стало бы слишком большой проблемой для анализаторов.
Что касается причины этого, черновик / дискуссионный документ N2215 Stroustrup и Dos Reis из 2007 года дают глубокое понимание многих проблем со списками инициализаторов в различных контекстах. В частности, есть раздел о бинарных операторах (раздел 6.2):
Рассмотрим более общее использование списков инициализаторов. Например:
v = v+{3,4}; v = {6,7}+v;
Когда мы рассматриваем операторы как синтаксический сахар для функций, мы, естественно, считаем, что вышеуказанное эквивалентно
v = operator+(v,{3,4}); v = operator+({6,7},v);
Поэтому естественно распространить использование списков инициализаторов на выражения. Во многих случаях списки инициализаторов в сочетании с операторами являются «естественной» нотацией.
Однако нетривиально написать грамматику LR (1), которая позволяет произвольно использовать списки инициализаторов. Блок также начинается с {, поэтому разрешение списка инициализаторов, поскольку первый (крайний левый) объект выражения может привести к хаосу в грамматике.
Тривиально разрешить списки инициализаторов в качестве правого операнда бинарных операторов в
подписи и тому подобные отдельные части грамматики. Настоящая проблема состоит в том, чтобы позволить;a={1,2}+b;
как оператор присваивания, не позволяя также;{1,2}+b;
, Мы подозреваем, что допускать списки инициализаторов в качестве правосторонних, но [sic] в качестве левых аргументов для большинства операторов — слишком много пустяков, […]