clang不会使用varargs

时间:2016-06-05 18:27:57

标签: c++ g++ c++14 variadic-templates clang++

考虑代码:

#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.

哪种编译器是对的?

1 个答案:

答案 0 :(得分:1)

代码格式不正确。两个编译器都无法正确编译:

#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]开始强调我的:

  

当一个函数参数包   出现在非推导的上下文(14.8.2.5)中,该参数包的类型从未推断

Args...出现在非推断的上下文中,因为来自[temp.deduct.type]:

  

非推断的上下文是:[...]一个函数参数包,它不会出现在 parameter-declaration-list 的末尾。

因此,根据标准的确切措辞,Args...不得推断,因此您必须明确提供 - 在这种情况下仍然无法实现T

但在这种情况下,Args...同时出现在推导出的非推断的上下文中 - 应该没有任何内容阻止Args...从{{1}中推断出来}参数为tuple,然后简单地重复使用对可变参数的推导,然后在最后推导{int, float, double}T

但是这个提议的过程会与我们独立处理每个参数/参数对的典型演绎过程发生冲突。在这种情况下,int上的扣除很大程度上取决于T参数/参数对中Args...的扣除。

如果您只是按顺序翻转:

tuple<>

然后两个编译器都编译它。

我不知道为什么gcc接受varargs的原始示例。这显然是错的。

此外,如果您翻转模板参数规范,以便您可以指定template <class... Args, class T> T method(std::tuple<Args...>, T, Args...) { ... } 而不需要扣除,那么clang接受但gcc拒绝:

T

我希望这个格式正确 - 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。因此,在我看来,“从未推断过”的措辞是值得怀疑的。