可变参数模板和省略号有什么区别?

What is the difference between variadic template and ellipsis?

我知道标题没有多大意义,但代码会解释我的问题。

template<typename T>
void foo(T...) {std::cout << 'A';}

template<typename... Ts>
void foo(Ts...) {std::cout << 'B';}

int main(){  
   foo(1); 
   foo(1,2);
}

在继续阅读之前尝试猜测这个程序的输出:

所以输出是AB

谁能解释为什么对于 1 个参数的函数优先给省略号,而对于 2 个参数的可变参数模板?

第一个重载到底是什么?

[dcl.fct]

Where syntactically correct and where “...” is not part of an abstract-declarator, “, ...” is synonymous with “...”.

所以这使得第一个重载成为一个可变参数函数(它也恰好是模板化的)相当于:

template<typename T>
void foo(T, ...) {std::cout << 'A';}

(N.B。cppreference 页面包含一个示例,其中第一个参数和可变参数之间的逗号类似省略。)

为什么我们会看到那个特定的输出?

当您传递两个参数时,编译器更喜欢 other 重载,因为在重载解析期间,在对可行的重载进行排名时,省略号转换序列总是排在最后。 ([over.ics.rank])

当传递单个参数时,编译器更喜欢第一个重载,因为简单地说,省略号不匹配(因为没有任何东西可以匹配)。这可以防止函数被视为省略号转换序列。然后发生正常函数模板排名,并确定此函数比可变函数更专业 ([temp.deduct.partial])

正在关注 overload_resolution#Best_viable_function

  • 对于f(1),

    我们通过 5)

    or, if not that, F1 and F2 are both template specializations and F1 is more specialized according to the partial ordering rules for template specializations

    Function_template_overloading

    After considering every P and A in both directions, if, for each type that was considered, [..]

    In case of a tie, if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack.

    所以省略函数 template<typename T> void foo(T,...) 被认为比可变函数 template<typename ...Ts> void foo(Ts...) 更专业。

  • 对于f(1, 2)

    阅读Ranking_of_implicit_conversion_sequences

    在可变版本中我们有精确匹配,而省略号有省略号转换序列

    所以可变参数更匹配。