为什么C++不支持强类型省略号?

Nic*_*ton 29 c++ ellipsis variadic-functions

有人可以向我解释为什么C++,至少据我所知,没有实现一个强类型的省略号函数,这是有效的:

void foo(double ...) {
 // Do Something
}
Run Code Online (Sandbox Code Playgroud)

这意味着,简单地说:'用户可以将可变数量的术语传递给foo函数,但是,所有术语必须是双倍的'

edm*_*dmz 23

 void foo(std::initializer_list<double> values);
 // foo( {1.5, 3.14, 2.7} );
Run Code Online (Sandbox Code Playgroud)

这非常接近.

您也可以使用可变参数模板,但它会更具有话语性.至于实际的原因,我会说引入新语法的努力可能不值得:你如何访问单个元素?你怎么知道什么时候停下来?比什么让它更好std::initializer_list呢?

C++确实有更接近的东西:非类型参数包.

template < non-type ... values>
Run Code Online (Sandbox Code Playgroud)

template <int ... Ints>
void foo()
{
     for (int i : {Ints...} )
         // do something with i
}
Run Code Online (Sandbox Code Playgroud)

但是非类型模板参数(uhm)的类型有一些限制:double例如,它不能.

  • 并且非类型模板参数的值有限制 - 它们必须是编译时常量表达式. (5认同)

Mat*_* M. 15

从历史上看,省略号语法...来自C.

这种复杂的野兽被用来驱动printf式的功能,并且与使用va_list,va_start等等...

如你所知,它不是类型安全的; 但是C远不是类型安全的,它与void*任何指针类型的隐式转换,它的隐式截断积分/浮点值等等...

因为C++作为C的超集尽可能接近,所以它继承了C的省略号.


自成立以来,C++实践得到了发展,并且一直在努力推动更强的打字.

在C++ 11中,这最终达到了:

  • 初始化列表,给定类型的可变数量值的简写语法: foo({1, 2, 3, 4, 5})
  • 可变参数模板,它们是自己的野兽,允许编写类型安全printf的例子

变量模板实际上...在语法中重用省略号,表示类型或值的,并作为解包运算符:

void print(std::ostream&) {}

template <typename T, typename... Args>
void print(std::ostream& out, T const& t, Args const&... args) {
    print(out << t, args...); // recursive, unless there are no args left
                              // (in that case, it calls the first overload
                              // instead of recursing.)
}
Run Code Online (Sandbox Code Playgroud)

注意3种不同的用途...:

  • typename... 声明一个可变参数类型
  • Args const&... 宣布一包参数
  • args... 在表达式中解压缩包

  • @Quentin:可变参数函数通常工作(今天)递归,所以你叫'有4个参数,它调用print``print`有3个参数,它调用`print`以2个参数,它调用`print` 1个参数= >这是基本情况(非可变函数),递归停止. (5认同)

Que*_*tin 11

可变模板和SFINAE已经可以实现:

template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;

template <class... Doubles, class = std::enable_if_t<
    all_true<std::is_convertible<Doubles, double>{}...>{}
>>
void foo(Doubles... args) {}
Run Code Online (Sandbox Code Playgroud)

感谢Columbo提供了很好的all_true技巧.您还可以在C++ 17中使用折叠表达式.

由于后来和即将出现的标准都集中在terser语法(简洁的for循环,隐式函数模板......)上,所提出的语法很可能在标准的一天内结束;)