首页 > 解决方案 > 为什么隐式转换不适用于模板化函数参数?

问题描述

我遇到了一些模板问题,我已将其范围缩小到以下示例 (C++17):

template <typename T> struct item {
  operator item<const T> () const { return item<const T>(); }
};

void conversionToConstRefWorks (const item<const int> &) { }

template <typename T> 
void butNotWhenTemplated (const item<const T> &) { }

int main () {

  item<int> i;
  item<const int> ci;

  // these all compile fine:
  conversionToConstRefWorks(ci);
  conversionToConstRefWorks(i);
  butNotWhenTemplated(ci);

  // but this one fails:
  butNotWhenTemplated(i); 

}

在那个例子中:

该示例的编译失败(GCC 9.3):

g++ --std=c++17 -W -Wall -pedantic -Wno-unused-variable    const_interop.cpp   -o const_interop
const_interop.cpp: In function ‘int main()’:
const_interop.cpp:54:24: error: no matching function for call to ‘butNotWhenTemplated(item<int>&)’
   54 |   butNotWhenTemplated(i);
      |                        ^
const_interop.cpp:40:6: note: candidate: ‘template<class T> void butNotWhenTemplated(const item<const T>&)’
   40 | void butNotWhenTemplated (const item<const T> &) {
      |      ^~~~~~~~~~~~~~~~~~~
const_interop.cpp:40:6: note:   template argument deduction/substitution failed:
const_interop.cpp:54:24: note:   types ‘const T’ and ‘int’ have incompatible cv-qualifiers
   54 |   butNotWhenTemplated(i);
      |                        ^

根本错误似乎是:

'const T' 和 'int' 类型具有不兼容的 cv 限定符

我理解字面意义上的意思,但我不明白为什么会这样。我的期望是item<int> :: operator item<const int> () const调用时会应用转换运算符,butNotWhenTemplated(i)就像调用时应用它一样conversionToConstRefWorks(i),并且int会为T.

我的主要问题是:为什么不编译?

我的另一个问题是:由于本文范围之外的原因,butNotWhenTemplated必须是模板并且必须指定<const T>所有item参数,并且在调用它时我无法显式指定模板参数。有没有办法在这些限制条件下完成这项工作?

这里是 ideone (GCC 8.3)。

标签: c++templatesgccc++17implicit-conversion

解决方案


item<int> i;
template <typename T> void butNotWhenTemplated (const item<const T> &) { }
butNotWhenTemplated(i); 

根据模板参数替换规则,找不到T匹配item<const T>item<int>。在考虑任何转换(内置或用户定义)之前,这会以硬错误方式失败。

类型推导不考虑隐式转换(除了上面列出的类型调整):这是重载解析的工作,稍后会发生。但是,如果参与模板实参推导的所有参数推导成功,并且所有未推导的模板实参都被显式指定或默认,则剩余的函数参数将与相应的函数实参进行比较。


推荐阅读