为什么隐式转换不适用于模板化函数参数?

Jas*_*n C 6 c++ gcc templates implicit-conversion c++17

我遇到了一些模板内容的问题,我已将范围缩小到以下示例 (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); 

}
Run Code Online (Sandbox Code Playgroud)

在那个例子中:

  • item<T>有一个隐式转换运算符 to item<const T>,和
  • 转换似乎在 中有效conversionToConstRefWorks(),但是
  • 在 中似乎错过了转换butNotWhenTemplated(),其中 anitem<const int>可以很好地传递但传递 anitem<int>无法编译。

该示例的编译失败(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);
      |                        ^
Run Code Online (Sandbox Code Playgroud)

根错误似乎是:

类型“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)上。

YSC*_*YSC 8

item<int> i;
template <typename T> void butNotWhenTemplated (const item<const T> &) { }
butNotWhenTemplated(i); 
Run Code Online (Sandbox Code Playgroud)

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

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