Когда требуется многоточие при работе с пакетами параметров?

#c #variadic-templates #parameter-pack

Вопрос:

Я пытаюсь понять какой-то код из cppreference.com. Соответствующая часть находится здесь

 template<typename... Ts>
std::ostreamamp; operator<<(std::ostreamamp; os, std::tuple<Ts...> constamp; theTuple)
{
    std::apply
    (
        [amp;os](Ts constamp;... tupleArgs)
        {
            os << '[';
            std::size_t n{ 0 };
            ((os << tupleArgs << (  n != sizeof...(Ts) ? ", " : "")), ...);
            os << ']';
        }, theTuple
    );
    return os;
}
 

Если я правильно интерпретирую вышесказанное ((os << tupleArgs << ( n != sizeof...(Ts) ? ", " : "")), ...) , это выражение сгиба над оператором запятой. Семантически это ([some pattern involving the parameter pack's values] , ...) означает складываться с запятой.

Чего я, однако, не понимаю, так это почему sizeof внутри есть sizeof... ? Для меня многоточие означает расширение, но мы не хотим расширяться там. Ts это похоже на агрегатный тип, похожий на кортеж, нам просто нужен размер во время компиляции этого агрегатного типа, пока компилятор оценивает сгиб. И действительно, в Visual Studio это работает в любом случае, с многоточием или без него. То же самое и в GCC, говорит мне Годболт. (ПРАВКА: на самом деле я ошибаюсь без многоточия, которое он компилирует, но вывод содержит конечную запятую, которой там быть не должно)

Является ли правилом просто всегда использовать sizeof... , если вам нужен размер пакета параметров?

Комментарии:

1. Видеть sizeof...

2. «И действительно, в Visual Studio это работает в любом случае, с многоточием или без него» — я подозреваю, что ваше тестирование было не совсем тщательным.

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

4. так sizeof(Ts) вернет ли размер отдельных типов при расширении и sizeof...(Ts) вернет ли размер пакета?

5. Ага. Это подводит итог.

Ответ №1:

Там нужны многоточия, потому sizeof...(Ts) что есть специальная форма sizeof , которая возвращает размер пакета параметров. Обычный sizeof(Ts) не может быть использован для этой цели, поскольку необходимо сохранить возможность использования стандартного sizeof поведения в расширенных шаблонах, т. е. sizeof(Ts) Возвращает размер отдельного типа в вычисляемом выражении сгиба.