请考虑以下事项:
template <class T> void Foo(const T* x) {
std::cout << "I am the pointer overload" << std::endl;
}
template <class T> void Foo(const T& x) {
std::cout << "I am the reference overload" << std::endl;
}
鉴于上述情况,我希望以下内容可以调用指针重载:
int* x;
Foo(x);
但它没有。这对我来说似乎很奇怪,因为const T*
可以明显地绑定到非const T
,就像const T&
一样,但指针变体看起来像是&#34;更合适&# 34。
对于我的应用程序,我希望调用指针变体。我可以通过额外的专业化来完成这项工作:
template <class T> void Foo(T* x) {
const T* const_x = x;
Foo(const_x);
}
但这感觉错了,没必要。有没有更好的办法?我不理解的是什么(标准的x.y.z部分除了这样说之外)?
答案 0 :(得分:25)
你在想:如果我的参数不是常量(或者如果参数是常量的)那么指针将是完美的匹配。这是正确的。 我所拥有的是const
。因此,只需在上面的场景中添加const
,我就会得到指针重载。那也是对的。现在怎么可能因为你明显得到了引用过载?嗯,代码与您的想法不符。这是与您的思路一致的代码,它确实会选择指针重载:
template <class T> void Foo(T* const x);
template <class T> void Foo(T const &x);
密切关注const
的位置。我添加了const
作为顶级限定符。虽然T const &x
与const T& x
相同,但T* const x
与const T* x
不同。
让我们看看在这种情况下的重载决议:
fun | T | parameter | argument
-----------------------------------------+------+--------------+-----------
template <class T> void Foo(T* const x) | int | int* const | int*
template <class T> void Foo(T const &x) | int* | int* const & | int*
让我们看看你的版本的重载:
fun | T | parameter | argument
-----------------------------------------+------+--------------+-----------
template <class T> void Foo(const T* x) | int | const int* | int*
template <class T> void Foo(T const &x) | int* | int* const & | int*
正如您在第一个版本中看到的那样,首选添加顶级const并选择指针重载。不需要指针转换。
在第二种情况下,指针重载需要从pointer to mutable
到pointer to const
的指针转换。这些是不同类型的指针。但是在第二次重载时,不需要指针转换。只需添加顶级const
。
简而言之,我能解释的最好的是标准的x.y.z部分
答案 1 :(得分:4)
您的问题是,在编译Foo(x);
时,会执行模板类型扣除,而且当您的x为int*
时,这将首先解释为Foo<int*>(x)
来电和您的{{ 1}}重载是一个完美的匹配,所以类型推导在这里结束。
如果要处理类(而不是模板函数),可以使用部分模板特化来区分指针类型和非指针类型,但对于函数,只允许完全特化。
您可以做的是使用SFINAE等技术:
template <class T> void Foo(const T& x)
在这种情况下,如果T是指针类型,则引用重载将不匹配(当扣除类型时),因此编译器也将尝试template <class T> void Foo(const T* x) {
std::cout << "I am the pointer overload" << std::endl;
}
template <class T>
typename std::enable_if<!std::is_pointer<T>::value>::type
Foo(const T& x) {
std::cout << "I am the reference overload" << std::endl;
}
并且您的Foo<int>(x)
重载将是完美匹配(正是你所期待的)。
样品:
template <class T> void Foo(const T* x)
输出:
int x = 12;
int* pX = new int(5);
Foo(x);
Foo(pX);