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

时间:2011-03-02 21:07:50

标签: 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 *版本?如何让它调用参考版本?

3 个答案:

答案 0 :(得分:15)

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而不是某些通用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第二次出错了。