代码之家  ›  专栏  ›  技术社区  ›  Jason C

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

  •  4
  • Jason C  · 技术社区  · 5 年前

    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); 
    
    }
    

    • item<T> 具有隐式转换运算符 item<const T>
    • 这种转变似乎在 conversionToConstRefWorks() ,但是
    • butNotWhenTemplated() item<const int> 可以很好的通过,但是 item<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);
          |                        ^
    

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

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

    为什么这不是编译?

    我的另一个问题是:出于本篇文章之外的原因, butNotWhenTemplated 必须是模板并且必须指定 <const T> 对所有人 item 参数,我不能在调用它时显式指定模板参数。有没有一种方法可以在这些限制条件下实现这一目标?

    Here it is on ideone (合同一般条款8.3)。

    2 回复  |  直到 5 年前
        1
  •  3
  •   YSC    5 年前
    item<int> i;
    template <typename T> void butNotWhenTemplated (const item<const T> &) { }
    butNotWhenTemplated(i); 
    

    根据 template argument substitution T item<const T> item<int>

        2
  •  1
  •   Gyross    5 年前

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

    附录:

    您试图通过引用传递const,但是隐式转换会创建对象的副本,即使在非模板的情况下也是如此。你可能需要重新考虑一下你的设计。