简体   繁体   English

具有两个参数包的函数模板重载决策

[英]Function template overload resolution with two parameter packs

Consider the following code: 请考虑以下代码:

#include<iostream>

template<class..., class... T>
int f(T...) { return 1; }

template<class... T>
int f(T...) { return 2; }

int main()
{
    std::cout << f(1);
}

It compiles and prints 1 on gcc 8.2, but fails to compile on clang 7 because of the call f(1) being ambiguous. 它在gcc 8.2上编译并打印1 ,但由于调用f(1)不明确而无法在clang 7上编译。

If the call is replaced by f() both compiler fail to compile claiming the call to be ambiguous. 如果调用被f()替换,则两个编译器都无法编译声称调用不明确。

If the parameter packs class... T are replaced with a simple parameter class T (and T... with T ), both compiler also claim ambiguity. 如果参数包class... T被简单的参数class T (和T... with T )替换,则两个编译器都声明歧义。

Which of the compiler is standard-conform in the first example? 在第一个示例中,哪个编译器符合标准? I suppose this comes down to the specific partial ordering rules for function templates, or is it already ill-formed to use the double parameter pack in this way? 我想这归结为功能模板的特定部分排序规则,还是以这种方式使用双参数包已经形成错误了?

Edit: 编辑:

My understanding is that the double pack is itself not ill-formed, because [temp.param] 17.1/15 in my reading seems to explicitly allow this if the second pack is deducible from the function arguments, which seems to be the case because of the T... function parameter pack. 我的理解是双包本身并不是格式错误,因为我的阅读中的[temp.param] 17.1 / 15似乎明确允许这个,如果第二个包可以从函数参数中推导出来,这似乎是因为T...功能参数包。

It is also possible to specify the first parameter pack's arguments explicitly, though not the second ones and so it is not always the case that (after template argument deduction) at least one parameter pack is empty. 也可以显式指定第一个参数包的参数,但不是第二个参数包的参数,因此并不总是(在模板参数推断之后)至少一个参数包为空。 I am not sure whether that makes the program ill-formed, because I don't know how to read eg [temp.res] 17.7/8.3 in this context. 我不确定这是否会使程序格式不正确,因为我不知道在这种情况下如何阅读例如[temp.res] 17.7 / 8.3。

Both gcc and clang seem to be fine with the double parameter pack itself, eg when the second function template overload is removed, both compiler print 1 . gcc和clang似乎都适用于双参数包本身,例如当第二个函数模板重载被删除时,两个编译器都打印1 But this might be a case of ill-formed, no diagnostic required . 但这可能是形成不良的情况,无需诊断

Furthermore I assume that with class template argument deduction, a variadic class template could have a variadic constructor template defined, which would imply a constructor candidate similar to my double parameter pack example and as far as I understand the same overload resolution and template argument deduction takes place in that context. 此外,我假设使用类模板参数推导,可变参数类模板可以定义一个可变参数构造函数模板,这意味着构造函数候选类似于我的双参数包示例,据我所知,相同的重载决议和模板参数推导需要在这种情况下。 This question was motivated by another question with such a setup: Variadic class template deduction fails with gcc 8.2, compiles with clang and msvc See also for a discussion on that: Deduction guides and variadic class templates with variadic template constructors - mismatched argument pack lengths 这个问题是由另一个带有这样一个设置的问题所驱动的: Variadic类模板推导失败了gcc 8.2,编译了clang和msvc参见讨论: 带有可变参数模板构造函数的演绎指南和可变参数类模板 - 不匹配的参数包长度

Now I have also found the answer to the question Deduction guide and variadic templates which I assume implies that gcc is wrong and the call should be considered ambiguous, but I would like to have it verified that this applies here the same way. 现在我也找到了问题的演绎指南和可变参数模板的答案,我假设gcc是错误的并且调用应该被认为是模棱两可的,但我想让它验证这适用于这里同样的方式。 I would also welcome in a bit more detail the reasoning, because the function template partial ordering rules seem very unclear to me. 我也会更加详细地欢迎推理,因为功能模板偏序规则对我来说似乎很不清楚。

There are two issues here. 这里有两个问题。


First, [temp.deduct.partial]/12 (I also quote the example since it is similar to yours) says: 首先, [temp.deduct.partial] / 12 (我也引用这个例子,因为它与你的相似)说:

In most cases, deduction fails if not all template parameters have values, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. 在大多数情况下,如果并非所有模板参数都具有值,则推导失败,但是对于部分排序目的,模板参数可以保持不带值,前提是它不用于用于部分排序的类型。 [ Note: A template parameter used in a non-deduced context is considered used. [注意:使用非推断上下文中使用的模板参数。 — end note ] [ Example: - 尾注] [示例:

 template <class T> T f(int); // #1 template <class T, class U> T f(U); // #2 void g() { f<int>(1); // calls #1 } 

— end example ] - 结束例子]

The types being used for partial ordering are T... according to [temp.deduct.partial]/3 : 根据[temp.deduct.partial] / 3,用于部分排序的类型是T...

The types used to determine the ordering depend on the context in which the partial ordering is done: 用于确定排序的类型取决于完成部分排序的上下文:

  • In the context of a function call, the types used are those function parameter types for which the function call has arguments. 在函数调用的上下文中,使用的类型是函数调用具有参数的函数参数类型。

  • ... ...

So the first unnamed template parameter pack class... does not affect the result of partial ordering. 所以第一个未命名的模板参数包class...不会影响部分排序的结果。 Since there are no other differences for the two function templates, neither is more specialized than the other, resulting an ambiguous call. 由于两个函数模板没有其他差异,因此两者都不比另一个更专业,从而导致模糊调用。

This may be related to bug 49505 of GCC. 可能与GCC的49505错误有关。


Second, even though the second function template does not exist, the call should still be ill-formed. 其次,即使第二个功能模板不存在,呼叫仍然应该是格式错误的。 According to [temp.arg.explicit]/3 : 根据[temp.arg.explicit] / 3

... A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments ... ...未以其他方式推导出的尾随模板参数包将被推导为空的模板参数序列......

Only trailing template parameter pack can be deduced to an empty pack, while the first unnamed template parameter pack class... is not a trailing template parameter pack. 只有尾随模板参数包可以推断为空包,而第一个未命名的模板参数包class...不是尾随模板参数包。

Both GCC ( bug 69623 ) and Clang ( bug 26435 ) have bugs for this issue. GCC( bug 69623 )和Clang( bug 26435 )都存在此问题的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM