C++ Primer第5版函数模板重载

6
在书籍《C++ Primer》中,有一个关于函数模板重载的例子:
// print any type we don't otherwise handle
template <typename T> string debug_rep(const T &t)
{
    cout << "debug_rep(T const&)\n";
    ostringstream ret; // see § 8.3 (p. 321)
    ret << t; // uses T's output operator to print a representation of t
    return ret.str(); // return a copy of the string to which ret is bound
}

// print pointers as their pointer value, followed by the object to which the pointer points
// NB: this function will not work properly with char*; see § 16.3 (p. 698)
template <typename T> string debug_rep(T *p)
{
    std::cout << "debug_rep(T*)\n";
    ostringstream ret;
    ret << "pointer: " << p << '\n';         // print the pointer's own value
    if (p)
        ret << " " << debug_rep(*p); // print the value to which p points
    else
        ret << " null pointer";      // or indicate that the p is null
    return ret.str(); // return a copy of the string to which ret is bound
}

If we call debug_rep with a pointer:

cout << debug_rep(&s) << endl;

both functions generate viable instantiations:

  • debug_rep(const string* &), which is the instantiation of the first version of debug_rep with T bound to string*

  • debug_rep(string*), which is the instantiation of the second version of debug_rep with T bound to string*

The instantiation of the second version of debug_rep is an exact match for this call.

The instantiation of the first version requires a conversion of the plain pointer to a pointer to const. Normal function matching says we should prefer the second template, and indeed that is the one that is run.

但是,如果我将指向字符串的指针声明为const,即使没有转换,第二个版本也总是被选择:

    string const s("hi"); // const
    cout << debug_rep(&s) << '\n';

我认为书中存在一个错误,并且我认为因为版本采用指针是首选,因为我们可以传递一个const或非const的指针(T将被推导为std::string const*std::string*)。

您怎么看?


1
C++ Primer的哪个版本? - Asteroids With Wings
1个回答

5

这本书是错误的。

在第一个例子中,生成的实例不是 debug_rep(const string* &),而是 debug_rep(string* const&)。也就是说,const 修饰的是指针,而不是所指向的内容。(如果该书使用正确的 const;即 template <typename T> string debug_rep(T const& t)作为第一个函数模板,则会更显然。)

事实上,TT const& 在函数模板重载方面具有相等的优先级;当它们组成重载集时,将产生歧义。选择 T* 而不是 T const& 的原因是它更为特化;简单来说,任意的 T* 可以传递给接受 T const& 的函数,而任意的 T const& 无法传递给接受 T* 的函数。


这有点解释了我的问题:https://godbolt.org/z/T43q34。这是否意味着在重载决议中涉及了“更专业化”的概念?(我本来期望两个实例都被实例化,然后再应用重载决议,但这将导致歧义。) - Daniel Langr
2
@DanielLangr 当然可以!如果一个函数模板被重载,且没有非模板可行函数,只有同样匹配程度的模板版本,则会选择更专业化的函数进行匹配,否则调用将是不明确的。 - Maestro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接