...(省略号)作为函数原型中唯一的函数参数在 C++ 中意味着什么?

What does ... (ellipsis) as one and only function parameter in a function prototype mean in C++?

我遇到过函数声明,例如:

int vsa_d(...);

... 作为一个且唯一的参数。

我知道用省略号可以指代多个对象,但是这里的...指的是什么?


我在“注释”下 https://en.cppreference.com/w/cpp/language/variadic_arguments 找到:

In the C programming language, at least one named parameter must appear before the ellipsis parameter, so printz(...); is not valid. In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution.

因此,它应用于“SFINAE”中的“回退过载”之类的任何事情。

这是什么意思?

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

在这里,vsa_d 可以接受任意数量的参数。

So, it shall be used for anything like a "fallback overload" in "SFINAE".

What does that mean?

示例:

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

... 参数在某些 SFINAE 结构中用作包罗万象。

这是关于编写类型特征 has_helloworld<T> 的问题 top answer 中的一个例外,它检测类型 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 被转换为指向的指针-member(-function) 并且选择了重载。 return 类型的大小是一个。

如果 typeof(&T::helloworld) 不存在 ,则该过载不在潜在的过载集中,并且选择回退 test(...) 作为过载。 return类型的大小是二。

test(...) 重载有一个很好的 属性,它总是 最差的 匹配,最后选择的重载。这意味着它可以作为此类结构中的 "fallback default"。