Что означает (многоточие) как единственный параметр функции в прототипе функции в С++?

Я наткнулся на объявление функции, например:

int vsa_d(...);

с ... в качестве единственного параметра.

Я знаю, что с помощью многоточия мы можем ссылаться на несколько объектов, но на что здесь указывает ...?

  • Что это значит и для чего предназначено?

  • Что ... оценивается компилятором?

  • Можно ли использовать многоточие также в качестве аргумента функции при вызове функции?


Я нашел здесь https://en.cppreference.com/w/cpp/language/variadic_arguments в разделе "Примечания":

В языке программирования C хотя бы один именованный параметр должен стоять перед параметром с многоточием, поэтому printz(...); не действует. В C++ эта форма разрешена, даже если аргументы, переданные такой функции, недоступны, и обычно используется в качестве резервной перегрузки в SFINAE, используя самый низкий приоритет преобразования многоточия в разрешении перегрузки.

Таким образом, он должен использоваться для чего-либо вроде «откатной перегрузки» в «SFINAE».

Что это значит?


person RobertS supports Monica Cellio    schedule 01.02.2020    source источник
comment
Он делает то же самое, что и в C. В C++ есть лучшие варианты, поэтому вам не следует его использовать.   -  person Jesper Juhl    schedule 01.02.2020
comment
@JesperJuhl Я процитирую кое-что, что нашел по этой теме: В языке программирования C по крайней мере один именованный параметр должен стоять перед параметром с многоточием, поэтому printz(...); недействителен. — en.cppreference.com/w/cpp/language /variadic_arguments в разделе Примечания.   -  person RobertS supports Monica Cellio    schedule 01.02.2020
comment
@JesperJuhl После этой цитаты в C нельзя кодировать таким образом, и это также причина, по которой я явно задал вопрос для C ++. Почему вы уверены, что это будет действительно в C?   -  person RobertS supports Monica Cellio    schedule 01.02.2020
comment
@JesperJuhl Я провел эксперимент на C и попытался скомпилировать его с помощью gcc; результат: error: ISO C requires a named argument before ‘...’   -  person RobertS supports Monica Cellio    schedule 01.02.2020
comment
@JesperJuhl Кажется, он используется для собственной обработки ошибок C++ или проверки: and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution.   -  person RobertS supports Monica Cellio    schedule 01.02.2020


Ответы (2)


Аргумент ... используется как универсальный в некоторых конструкциях SFINAE.

Вот исключение из верхнего ответа на вопрос о написании признака типа has_helloworld<T>, который определяет, имеет ли тип T член helloworld:

template <typename T>
class has_helloworld
{
    typedef char one;
    struct two { char x[2]; };

    template <typename C> static one test( typeof(&C::helloworld) ) ;
    template <typename C> static two test(...);    

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

int main(int argc, char *argv[])
{
    std::cout << has_helloworld<Hello>::value << std::endl;
    std::cout << has_helloworld<Generic>::value << std::endl;
    return 0;
}

Это работает следующим образом: если typeof(&T::helloworld) существует и является правильно сформированным, то на сайте test<T>(0) константа 0 преобразуется в указатель на элемент(-функцию) и выбирается эта перегрузка. Размер возвращаемого типа равен единице.

Если typeof(&T::helloworld) не существует, то такой перегрузки нет в наборе потенциальных перегрузок, и в качестве перегрузки выбирается резервный вариант test(...). Размер возвращаемого типа равен двум.

У перегрузки test(...) есть приятное свойство: она всегда является наихудшим-соответствующим перегруженным вариантом, выбранным последним. Это означает, что он может служить «запасным вариантом по умолчанию» в таких конструкциях.

person NicholasM    schedule 01.02.2020
comment
Я думаю, стоит отметить, что typeof является расширением GCC, а не стандартным, но вместо него будет работать decltype. - person aschepler; 02.02.2020

int vsa_d(...); // can take any number of arguments

Здесь vsa_d может принимать любое количество аргументов.

Таким образом, он должен использоваться для чего-либо вроде «запасной перегрузки» в «SFINAE».

Что это значит?

Пример:

template <typename T>
struct has_f {
  template <typename U, typename = decltype(std::declval<U&>().f())>
  static std::true_type foo(U);

  static std::false_type foo(...);

  using type = typename decltype(foo(std::declval<T>()))::type;
};

struct a {
  void f(){}
};

Здесь foo имеет две перегрузки:

template <typename U, typename = decltype(std::declval<U&>().f())>
static std::true_type foo(U);

Если выражение decltype(std::declval<U&>().f() допустимо, то то, с чем мы вызвали has_f, действительно имеет функцию f, и будет выбрана эта перегрузка.

В противном случае будет выбрана функция-член, не являющаяся шаблоном.

static std::false_type foo(...);

Потому что у него самый низкий приоритет.


Вызов

std::cout << std::boolalpha << has_f<a>::type();

дает

true
person Andreas DM    schedule 01.02.2020