clang 不使用可变参数推断可变参数模板函数中的模板参数
clang does not infer template argument in variadic template function with varargs
考虑代码:
#include <tuple>
template<class... Args, class T>
T method(std::tuple<Args...>, Args..., T, ...) {
return T();
}
int main() {
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
1, 1.0f, 1.0, 1);
}
g++
从4.9开始编译就没有问题了。另一方面,clang++
提供了一个错误:
main.cpp:9:5: error: no matching function for call to 'method'
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
^~~~~~
main.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T'
T method(std::tuple<Args...>, Args..., T, ...) {
^
1 error generated.
哪个编译器是正确的?
代码格式错误。两个编译器都正确地编译失败:
#include <tuple>
template<class... Args, class T>
T method(std::tuple<Args...>, Args..., T) {
return T();
}
int main() {
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
1, 1.0f, 1.0, 1);
}
我们确实有,来自 [temp.deduct.call],强调我的:
When a function parameter pack
appears in a non-deduced context (14.8.2.5), the type of that parameter pack is never deduced.
Args...
出现在非推导上下文中,因为来自 [temp.deduct.type]:
The non-deduced contexts are: [...] A function parameter pack that does not occur at the end of the parameter-declaration-list.
因此,根据标准的确切措辞,不应推导出 Args...
,因此您必须明确提供它 - 在这种情况下,这仍然不可能归因于 T
。
但在这种情况下,Args...
出现在推导的 和 非推导的上下文中 - 应该没有什么可以阻止 Args...
从tuple
参数为 {int, float, double}
,然后简单地重新使用可变参数的推导,最后将 T
推导为 int
。
但是 这个提议的过程会与我们独立处理每个 parameter/argument 对的典型推导过程冲突。在这种情况下,T
的推导很大程度上取决于 tuple<>
parameter/argument 对 Args...
的推导。
如果您简单地翻转顺序:
template <class... Args, class T>
T method(std::tuple<Args...>, T, Args...) { ... }
然后两个编译器都会编译它。
我不知道为什么 gcc 接受带有可变参数的原始示例。这显然是错误的。
此外,如果您翻转模板参数规范以便您可以指定 T
而无需扣除,则 clang 接受但 gcc 拒绝:
template<class T, class... Args>
T method(std::tuple<Args...>, Args..., T) {
return T();
}
int main() {
method<int>(std::make_tuple<int>(1), 1, 1);
}
我希望它是合式的 - Args...
可以推导出来,而 T
不一定是。所以 "never deduced" 上的措辞在我看来是有问题的。
考虑代码:
#include <tuple>
template<class... Args, class T>
T method(std::tuple<Args...>, Args..., T, ...) {
return T();
}
int main() {
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
1, 1.0f, 1.0, 1);
}
g++
从4.9开始编译就没有问题了。另一方面,clang++
提供了一个错误:
main.cpp:9:5: error: no matching function for call to 'method'
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
^~~~~~
main.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T'
T method(std::tuple<Args...>, Args..., T, ...) {
^
1 error generated.
哪个编译器是正确的?
代码格式错误。两个编译器都正确地编译失败:
#include <tuple>
template<class... Args, class T>
T method(std::tuple<Args...>, Args..., T) {
return T();
}
int main() {
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
1, 1.0f, 1.0, 1);
}
我们确实有,来自 [temp.deduct.call],强调我的:
When a function parameter pack appears in a non-deduced context (14.8.2.5), the type of that parameter pack is never deduced.
Args...
出现在非推导上下文中,因为来自 [temp.deduct.type]:
The non-deduced contexts are: [...] A function parameter pack that does not occur at the end of the parameter-declaration-list.
因此,根据标准的确切措辞,不应推导出 Args...
,因此您必须明确提供它 - 在这种情况下,这仍然不可能归因于 T
。
但在这种情况下,Args...
出现在推导的 和 非推导的上下文中 - 应该没有什么可以阻止 Args...
从tuple
参数为 {int, float, double}
,然后简单地重新使用可变参数的推导,最后将 T
推导为 int
。
但是 这个提议的过程会与我们独立处理每个 parameter/argument 对的典型推导过程冲突。在这种情况下,T
的推导很大程度上取决于 tuple<>
parameter/argument 对 Args...
的推导。
如果您简单地翻转顺序:
template <class... Args, class T>
T method(std::tuple<Args...>, T, Args...) { ... }
然后两个编译器都会编译它。
我不知道为什么 gcc 接受带有可变参数的原始示例。这显然是错误的。
此外,如果您翻转模板参数规范以便您可以指定 T
而无需扣除,则 clang 接受但 gcc 拒绝:
template<class T, class... Args>
T method(std::tuple<Args...>, Args..., T) {
return T();
}
int main() {
method<int>(std::make_tuple<int>(1), 1, 1);
}
我希望它是合式的 - Args...
可以推导出来,而 T
不一定是。所以 "never deduced" 上的措辞在我看来是有问题的。