模板参数推导:哪个编译器就在这里?

时间:2015-10-01 15:31:45

标签: c++ c++11 g++ clang language-lawyer

请考虑以下代码:

template<int N>
class Vector
{
};

#include <array>

template<int N>
void doWork(const Vector<N>&, const std::array<int,N>&)
{
}

int main()
{
    std::array<int,3> arr;
    Vector<3> vec;
    doWork(vec,arr);
}

此处Vector表示在第三方库中定义的类,已知std::array将其元素计为std::size_t

我尝试用clang-3.6和g ++ - 5.1编译它。 Clang没有任何投诉,而g ++给出了以下错误:

test.cpp: In function ‘int main()’:
test.cpp:17:19: error: no matching function for call to ‘doWork(Vector<3>&, std::array<int, 3ul>&)’
     doWork(vec,arr);
                   ^
test.cpp:9:6: note: candidate: template<int N> void doWork(const Vector<N>&, const std::array<int, N>&)
 void doWork(const Vector<N>&, const std::array<int,N>&)
      ^
test.cpp:9:6: note:   template argument deduction/substitution failed:
test.cpp:17:19: note:   mismatched types ‘int’ and ‘long unsigned int’
     doWork(vec,arr);
                   ^
test.cpp:17:19: note:   ‘std::array<int, 3ul>’ is not derived from ‘const std::array<int, N>’

我可以通过在N的第二个参数中调用std::size_tdoWork()或调用doWork<3>()来解决此问题,但这不会教育我。< / p>

所以我首先要问:哪个编译器就在这里?我真的在代码中做错了(所以clang太宽容了),还是它确实是有效的C ++(所以g ++有一个bug)?

1 个答案:

答案 0 :(得分:4)

我相信gcc在这里是正确的,如果我们去草案C ++ 11标准部分14.8.2.5 [temp.deduct.type] 它说:

  

如果,在声明一个非类型的函数模板   template-parameter,非类型模板参数用于   函数参数列表中的表达式,如果相应的话   推导出template-argument,模板参数类型必须匹配   完全是模板参数的类型,除了a   从数组绑定推导出的模板参数可以是任何积分   type.144 [例如:

template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
     

[...]

我们可以看看我们是否将代码更改为:

doWork<3>(vec,arr);

gcc不会发出错误,也不会发出铿锵声。

如果我们尝试这个例子:

template<int N>
void doWorkB( std::array<int,N>&)
{
}

//...

doWorkB(arr);

clang现在会产生错误( see it live ):

note: candidate template ignored: substitution failure : deduced non-type template argument does not have the same type as the its corresponding template parameter ('unsigned long' vs 'int')
void doWorkB( std::array<int,N>&)
     ^

如果我们交换参数顺序,你的原始案例也会在clang中断:

void doWork( const std::array<int,N>&, const Vector<N>& )