Яке значення лексеми “……”? тобто оператор подвійного еліпсису в пакеті параметрів


110

Переглядаючи поточну реалізацію нових заголовків C ++ 11 gcc, я натрапив на маркер "......". Ви можете переконатись, що наступний код складається добре [через ideone.com].

template <typename T>
struct X
{ /* ... */ };

template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
{ /* ... */ };

Отже, у чому сенс цього лексема?

редагувати: Схоже, ТАК підстрижений "......" у назві питання на "...", я дійсно мав на увазі "......". :)


підказка: за ним ...слідує ....
Олександр К.

5
Хіба це не більше, як U...за ним .... Однак дуже дивно.
edA-qa mort-ora-y

1
Примітка: Це можна знайти в <functional>і <type_traits>завжди в контексті списку аргументів функції всередині параметра шаблона.
Potatoswatter

Єдиний спосіб, коли я виявив, що він застряг у назві, - це простір між ними ... сподіваюся, що це стане зрозумілішим для читачів.
Матьє М.

@Matthieu M .: Спасибі, набагато краще!
Вітус

Відповіді:


79

Кожен екземпляр цієї дивацтва поєднується із випадком регулярного одиничного еліпсису.

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
    { typedef _Res result_type; };

Я здогадуюсь, що подвійний еліпсис схожий за своїм значенням _ArgTypes..., ..., тобто варіативне розширення шаблону з подальшим списком вараг у стилі С.

Ось тест, який підтверджує цю теорію ... Я думаю, що у нас є новий переможець для найгіршого псевдооператора коли-небудь.

Редагувати: це, здається, відповідає. § 8.3.5 / 3 описує один із способів формування списку параметрів як

параметр-декларація-список opt ... opt

Таким чином, подвійний еліпсис формується списком-декларацією параметрів, що закінчується пакетом параметрів, а потім - іншим еліпсісом.

Кома є суто необов’язковою; § 8.3.5 / 4 говорить

Там, де синтаксично правильно і де "..." не входить до конспекту-декларатора, ", ..." є синонімом "...".

Це знаходиться в абстрактному-опису, [ред] , але Johannes робить хорошу точку , що вони мають в виду абстрактну-опису в параметрі-декларації. Цікаво, чому вони не сказали "частина декларації параметра", і чому це речення не є просто інформаційною запискою ...

Крім того, va_begin()в <cstdarg>вимагає параметра перед змінною довжиною списку, тому прототип f(...)спеціально дозволено C ++ марно. Перехресне посилання на C99 є незаконнім у звичайній C. Отже, це найбільш химерно.

Примітка про використання

За запитом, ось демонстрація подвійного еліпсису:

#include <cstdio>
#include <string>

template< typename T >
T const &printf_helper( T const &x )
    { return x; }

char const *printf_helper( std::string const &x )
    { return x.c_str(); }

template< typename ... Req, typename ... Given >
int wrap_printf( int (*fn)( Req... ... ), Given ... args ) {
    return fn( printf_helper( args ) ... );
}

int main() {
    wrap_printf( &std::printf, "Hello %s\n", std::string( "world!" ) );
    wrap_printf( &std::fprintf, stderr, std::string( "Error %d" ), 5 );
}

Так, правильно. T (U ..., ...), однак, також складає штраф; можливо, вони хотіли заощадити трохи місця. :)
Вітус

1
Але що це означатиме? І як компілятор може сказати, де закінчуються _ArgTypes і які "зайві" параметри починаються?
Бо Персон

12
@Bo Persson: std::is_function«s valueмає бути істинним , навіть якщо функція З однієї змінної довжини і тому , що T (U ...) це НЕ відповідає такій функції, вам потрібно це безумство. Наприклад, int f (int, char, ...) збігається з T (U ......) саме з T = int, U = {int, char} і токером "..." varargs.
Вітус

4
"Це в межах абстрактного декларатора" -> вони означають, що не є частиною абстрактного декларатора останнього параметра цього ж списку типів параметрів. Наприклад void (int...), ...не є частиною абстрактного декларатора int, отже, це синонім void(int, ...). Якщо ви пишете void(T...)і Tє пакетом параметрів шаблону, він ...був би частиною реферату-декларатора, а значить, він не був би еквівалентним void(T, ...).
Йоханнес Шауб - ліб

2
"Крім того, va_begin () у <cstdarg> вимагає параметр перед списком varargs, тому прототип f (...), дозволений спеціально C ++, є марним." - Марно лише, якщо ви хочете знати, які аргументи були передані. f(...)використовується дуже сильно як резервна функція перевантаження в метапрограмуванні шаблонів, де ця інформація не потрібна (і де функція навіть фактично не викликається).

4

на версію шаблона vs2015 важливо:

    template <typename T, typename ... U>
    struct X<T(U...,...)> {};// this line is the important one

Приклад інстанції:

    X<int(int...)> my_va_func;

з повагою, FM.


Я теж це помітив, це все ще трапляється. Повідомлення помилки в developercommunity.visualstudio.com/content/problem/437260 / ... .
egyik

Добре знати. Будь-які посилання чи цитати на стенд з цього приводу?
Red.Wave

.سلام ببخشید نمیدانم
egyik

Це публічний форум. Нехай люди читають те, що ти думаєш. PLZ зберігає рідну мову для приватних повідомлень. سپاس.
Red.Wave

Добре тоді. Я не є експертом зі стандарту - я думаю, що інші детально висвітлювали це вище. Якщо комусь цікаво коментувати звіт про проблеми Microsoft, то це може підвищити його пріоритет. У звіті показано, що кланг та gcc дозволяють, що VC ++ не робить, я думаю, що ми, мабуть, на досить сильній основі.
egyik
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.