模板类型参数相对于引用和指针的函数重载解析

问题描述 投票:0回答:1

我一直在编写一些代码作为练习。

template <typename T> const T& larger(const T& a, const T& b) {
    std::cout << "Calling larger(const T&, const T&)" << std::endl;
    return a > b ? a : b;
}

template <typename T> const T* larger(const T* a, const T* b) {

    std::cout << "Calling larger(const T*, const T*)" << std::endl;

    return *a > *b ? a : b;
}

int main() {


    int a { 1 }, b { 2 };
    std::cout << larger(a, b) << std::endl;

    int *c { new int { 5 } }, *d { new int { 4 } };

    std::cout << *larger<int>(c, d) << std::endl;

    return 0;

}

有几件事我不明白。首先,为什么编译器将对 main 中的

larger()
函数的调用解析为接受引用参数的模板。在第二次调用larger时,推导的类型不应该是
int*
,因此,调用接受指针参数的函数吗?

我确实知道我可以通过使用显式类型参数调用第二个函数来“解决”我的问题

larger<int>(c, d)
(它有效,但我不知道为什么)。不过,我更感兴趣的是了解这种场景的类型推导规则?

c++ pointers templates reference type-deduction
1个回答
0
投票

首先看一下将左值指针传递给 int 时推导出来的结果。

第一个变成了

template<T=int*>
int * const& larger(int* const&, int*const&);

第二个变成

template<T=int>
int const* larger(int const*, int const*);

(我统一使用 east-const 风格,因为这样更清晰:被 const 修饰的类型部分位于 const 关键字的左侧。)

在 const& 到精确类型匹配和隐式转换到更 const 指针之间做出决定时,对精确类型匹配的 const 的引用获胜。

您可以通过多种方式避免这种情况。您可以使用 require 子句或 sfinae 来阻止 T 作为第一个模板重载中的指针。另外,你可以确保第二个是对第一个的严格限制。

代码中最后一个烦人的问题是,如果你传递纯右值,你会得到一个悬空引用。

我自己,我会从比较中分得更大。然后做

template<class T>
T larger(T&& a,T&& b){
  if (compare(a,b))
    return std::forward<T>(a);
  else
    return std::forward<T>(b);
}

现在比较必须担心比较指针与非指针,而不是担心是否返回悬空引用。

(一个更高级的更大的方法可以处理一个纯右值,另一个不使用 std 常见类型之类的东西)。

© www.soinside.com 2019 - 2024. All rights reserved.