在C ++中传递对数组的引用

任何人都可以帮我理解下面的代码

#include <iostream> void foo(const char * c) { std::cout << "const char *" << std::endl; } template <size_t N> void foo(const char (&t) [N]) { std::cout << "array ref" << std::endl; std::cout << sizeof(t) << std::endl; } int main() { const char t[34] = {'1'}; foo(t); char d[34] = {'1'}; foo(d); } 

输出是

 const char * array ref 34 

为什么第一个foo调用const char *版本? 我怎样才能叫它的参考版本?

const char[N]转换为const char*被认为是“完全匹配”(主要是为了使文字更容易),并且在两个完全匹配之间,非模板函数优先。

你可以使用enable_ifis_array来强制它做你想做的事情。


凌乱的方式来强制它可能是:

 #include <iostream> template <typename T> void foo(const T* c) { std::cout << "const T*" << std::endl; } template <typename T, size_t N> void foo(const T (&t) [N]) { std::cout << "array ref" << std::endl; } int main() { const char t[34] = {'1'}; foo(t); char d[34] = {'1'}; foo(d); } /* array ref array ref */ 

我意识到,OP有char不是一个genericsT ,但是这表明问题在于一个超载是模板而不是另一个。

让我们看看这个没有模板的修改示例。

 void foo(const char * c) { std::cout << "const char *" << std::endl; } void foo(const char (&t) [34]) { std::cout << "const char (&) [34]" << std::endl; } int main() { const char t[34] = {'1'}; foo(t); } 

我的编译器说,重载foo调用是不明确的。 这是因为从数组到指针的转换被认为是“精确的”转换序列,并不比重载分辨率的空转换序列好(标准第13.3.3.1.1节)。

在原始代码中,模板参数N可以推导为34,但是在重载分辨率中考虑非模板foo(const char*)foo<34>(const char (&)[34]) 。 由于转换规则既不比另一个更好,非模板函数也会跳过模板函数。

修复事情似乎很棘手。 看起来好像来自头<type_traits>is_array模板(如果可能的话,从C ++ 0x开始,或者如果没有的话,Boost)可能会有所帮助。

这对于各种编译器来说似乎是不同的。

Mircosoft和Borland都使用const char *版本,而GNU则给出你描述的输出。

这里是C ++标准的片段:

14.8.2.1从函数调用中推导模板参数[temp.deduct.call]

通过比较每个函数模板参数types(称为P)和调用的相应参数的types(称为A)来完成模板参数推导,如下所述。

如果P不是参考types:

– 如果A是数组types,则使用由数组到指针标准转换(4.2)生成的指针types来代替A来进行types推导; 除此以外,

– 如果A是一个函数types,则使用函数对指针标准转换(4.3)生成的指针types来代替A来进行types推导; 除此以外,

– 如果A是cv限定types,Atypes的顶级cv限定符将被忽略。

如果P是一个cv限定types,那么Ptypes的顶级cv限定符将被忽略。 如果P是参考types,则P所指的types用于types推导

编译器将build立一个列表如下:

 Argument: td A: char const[34] char[34] 

和参数列表P

 Parameter: ct P: char const* char const& t[N] 

默认情况下,编译器应该select未引用的参数。 由于某种原因,GNU第二次出错了。