任何人都可以帮助我理解以下代码
#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 *
版本?如何让它调用参考版本?
答案 0 :(得分:15)
将const char[N]
转换为const char*
被视为“完全匹配”(主要是为了使文字更容易),并且在两个完全匹配之间,非模板函数优先。
您可以使用enable_if
和is_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
而不是某些通用T
,但是这表明问题在于一个重载是模板而不是另一个。
答案 1 :(得分:5)
让我们看看这个没有模板的修改过的例子。
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])
都被认为是重载决策。由于转换规则两者都不比另一个好,因此非模板函数胜过模板函数。
修复事情似乎很棘手。看起来像标题is_array
中的<type_traits>
模板(如果可能的话,来自C ++ 0x,或者如果没有,则来自Boost)可能有帮助。
答案 2 :(得分:1)
对于各种编译器,这似乎有所不同。
Mircosoft和Borland都使用const char *版本,而GNU则提供你描述的输出。
以下是C ++标准的摘录:
14.8.2.1从函数调用中推导出模板参数 [temp.deduct.call]
模板参数推断由。完成 比较每个功能模板 参数类型(称之为P)与 相应参数的类型 如上所述的呼叫(称之为A) 下方。
如果P不是参考类型:
- 如果A是数组类型,则由数组到指针生成指针类型 标准转换(4.2)用于 A类型的扣除; 否则,
- 如果A是函数类型,则由指针类型生成 功能指针标准 转换(4.3)用于代替A. 用于类型扣除;否则,
- 如果A是cv限定类型,则是A类型的顶级cv限定符 因类型扣除而被忽略。
如果P是cv限定类型,则顶部 P类型的等级cv限定符是 忽略类型扣除。如果P是a 引用类型,引用的类型 由P用于类型推导
编译器将构建一个A
列表,如下所示:
Argument: t d
A: char const[34] char[34]
参数列表P
:
Parameter: c t
P: char const* char const& t[N]
默认情况下,编译器应选择未引用的参数。由于某种原因,GNU第二次出错了。