为什么';tc++;支持强类型省略号吗? >有人能解释一下为什么C++,至少在我的知识里,没有实现强类型省略号函数,有些东西的效果是: void foo(double ...) { // Do Something }

为什么';tc++;支持强类型省略号吗? >有人能解释一下为什么C++,至少在我的知识里,没有实现强类型省略号函数,有些东西的效果是: void foo(double ...) { // Do Something },c++,variadic-functions,ellipsis,C++,Variadic Functions,Ellipsis,这意味着,简单地说:“用户可以向foo函数传递数量可变的术语,但是,所有术语都必须是双精度的”,因为您可以使用 void foo(std::vector<T> values); void foo(标准::向量值); 实现(某种程度上)您建议的方法是使用可变模板 template<typename... Arguments> void foo(Arguments... parameters); 模板 void foo(参数…参数); 但是,现在可以在参数包中传递任何类

这意味着,简单地说:“用户可以向foo函数传递数量可变的术语,但是,所有术语都必须是双精度的”

,因为您可以使用

void foo(std::vector<T> values);
void foo(标准::向量值);
实现(某种程度上)您建议的方法是使用可变模板

template<typename... Arguments>
void foo(Arguments... parameters);
模板
void foo(参数…参数);
但是,现在可以在参数包中传递任何类型。 您提出的建议从未实现过,可能是对语言的一个很好的补充,也可能只是目前的情况下很难实现。你可以试着写一份提案并提交给isocpp.org

 void foo(std::initializer_list<double> values);
 // foo( {1.5, 3.14, 2.7} );
喜欢

template <int ... Ints>
void foo()
{
     for (int i : {Ints...} )
         // do something with i
}
模板
void foo()
{
for(inti:{Ints…})
//和我一起做点什么
}

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

可变模板和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) {}
模板结构文件包;
模板
使用all_true=std::is_same;
模板>
void foo(double…args){}
感谢您的精彩的
all_true
技巧。您还可以在C++17中使用折叠表达式


由于后来和即将推出的标准都将重点放在简洁的语法上(对于循环、隐式函数模板……),因此很可能有一天您提出的语法最终会出现在标准中;)

我不知道为什么这样的事情没有被提出(或者被提出并被拒绝)。这样的东西当然会有用,但会增加语言的复杂性。正如所演示的,已经有人提出了一种C++11使用模板实现这种功能的方法

当概念添加到标准中时,我们将采用另一种更简洁的方式:

template <Convertible<double>... Args>
void foo(Args... doubles);
模板
无效foo(Args…双倍);

模板
需要可转换的:

void foo(可转换…双倍);

就我个人而言,在目前的解决方案和我们将从概念中得到的解决方案之间,我认为这是解决问题的一个适当的解决方案。特别是因为最后一个基本上就是你最初想要的

历史上,省略语法
来自C

这个复杂的beast用于为类似printf的函数供电,并与
va_list
va_start
等一起使用

正如您所指出的,它不是类型安全的;但是C远远不是类型安全的,因为它对任何指针类型进行了从和到
void*
的隐式转换,它对积分/浮点值的隐式截断,等等

因为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.)
}
void打印(std::ostream&){
模板
无效打印(标准::ostream&out、T const&T、Args const和…Args){
打印(输出<代码>模板
结构相同;
模板
结构是相同的{static const bool value=std::is_same::value&&are_same::value;};
模板
结构是相同的{static const bool value=true;};
模板
使用requires_same=std::启用\u if\u t;
模板
void foo(参数…参数)
{
}
基于:

voidfoo(){}
模板
void foo(双参数,Rest…Rest)
{
/*用arg做点什么*/
傅(休息…);
}

如果使用
foo
编译的代码,您知道所有参数都可以转换为
double

,我猜变量函数被添加到C中的唯一目的是支持printf函数族,它必须是类型不安全的。格式字符串I/O概念本身可能是从C的前辈那里获得的在现代C++中,不需要引入类型安全的变量函数,因为我们有优越的语言结构,尤其是C++ 11。不幸的是,我没有猜测我的猜测。如果Bjarne Stroustrup自己问这个问题,你会很有趣。<代码> >调用< <代码> fo((double []){1,1,3.4},5})/gord> C++。扩展:没有PNTF家族必须类型不安全的根本原因。C可以声明实现首先推“类型令牌”。在调用堆栈上,vararg机制可以检查堆栈上是否存在正确类型的值。这会减慢正确的代码的速度,而且C在历史上强烈偏好“快于安全”。@MSalters:OTOH,这仍然不会使它在编译时具有类型安全性。@user3528438
使用id=T的模板;void foo(double*);foo(id{1,2,3,4});
在没有扩展的情况下运行良好……这是类型安全的,但只允许单一类型……而且不是很“自然”调用。我严重怀疑这是原因。另外,这根本不是同一种事情。@juan,请详细说明。OP想要一个具有可变参数量的函数的模拟,所有参数都是单一类型的(这是明确说明的).现在,与之相比,我们这里有什么?数量可变的未命名参数?检查。能够计算实际传递的参数并获得它们的值吗?检查。当然,这不是原因,但是,我认为
template <typename... Args>
    requires Convertible<Args, double>()...
void foo(Args... doubles);
void foo(Convertible<double>... doubles);    
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.)
}
template<typename T, typename... Arguments>
struct are_same;

template <typename T, typename A1, typename... Args>
struct are_same<T, A1, Args...>{    static const bool value = std::is_same<T, A1>::value && are_same<T, Args...>::value;};

template <typename T>
struct are_same<T>{static const bool value = true;};

template<typename T, typename... Arguments>
using requires_same = std::enable_if_t<are_same<T, Arguments...>::value>;

template <typename... Arguments, typename = requires_same<double, Arguments...>>
void foo(Arguments ... parameters)
{
}
void foo () {}

template <typename... Rest>
void foo (double arg, Rest... rest)
{
    /* do something with arg */
    foo(rest...);
}