C++模板推导——T成为指针类型

C++ template deduction - T becomes a pointer type

我有这个代码片段

template <typename T>
void p(const T* value)
{
  std::cout << *value << std::endl;
}

template <typename T>
void p(const T& value)
{
  std::cout << value << std::endl;
}

int main()
{
  int* i = new int(5);
  p(i);
}

1) 根据https://cppinsights.io/,模板函数等同于

template <typename T>
void p(const T* value)
{
  std::cout << *value << std::endl;
}

template <typename T>
void p(const T& value)
{
  std::cout << value << std::endl;
}

/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void p<int *>(int *const & value)
{
  std::cout.operator<<(value).operator<<(std::endl);
}
#endif 

对我来说这很奇怪。根据 "Item 1 of Effective modern c++",T 可以推断为 T&(或我猜是 T*)的唯一情况是函数参数是通用引用(转发引用)。然而这种情况下 T 被推导为 int*,但参数只是一个指针。

2) 如果我替换

int* i = new int(5);

const int* i = new int(5);

这是结果 (我对第一名的期望)

template <typename T>
void p(const T* value)
{
  std::cout << *value << std::endl;
}

/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void p<int>(const int * value)
{
  std::cout.operator<<(*value).operator<<(std::endl);
}
#endif


template <typename T>
void p(const T& value)
{
  std::cout << value << std::endl;
}

3) 回到 1),如果我去掉重载

template <typename T>
void p(const T& value)

所以我只有

template <typename T>
void p(const T* value)
{
  std::cout << *value << std::endl;
}

int main()
{
  int* i = new int(5);
  p(i);
}

结果是

template <typename T>
void p(const T* value)
{
  std::cout << *value << std::endl;
}

/* First instantiated from: insights.cpp:12 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void p<int>(const int * value)
{
  std::cout.operator<<(*value).operator<<(std::endl);
}
#endif


int main()
{
  int * i = new int{5};
  p(i);
}

你能解释一下为什么问题1)中的T可以推导为int*吗?问题2)中的int? 我也不明白模板参数推导的顺序 3).

感谢任何提示/解释。

int *int * const &的隐式转换序列优于从int *const int *的隐式转换序列。

后者有qualification conversion,前者没有

模板参数推导是在回答问题 "what type do I substitute T for",而不是 "what is the type of value"。对于 template <typename T> void p(const T* value) 必须 从参数类型中删除 *