【问题标题】:How to use template function for implicit conversion如何使用模板函数进行隐式转换
【发布时间】:2019-10-22 15:55:03
【问题描述】:

非常简化示例(不管A 类和操作员在做什么,这只是示例):

#include <iostream>
using namespace std;

template <bool is_signed>
class A {
public:
    // implicit conversion from int
    A(int a) : a_{is_signed ? -a : a}
    {}

    int a_;
};

bool operator==(A<true> lhs, A<true> rhs) {
    return lhs.a_ == rhs.a_;
}

bool operator==(A<false> lhs, A<false> rhs) {
    return lhs.a_ == rhs.a_;
}

int main() {
    A<true> a1{123};
    A<false> a2{123};

    cout << (a1 == 123) << endl;
    cout << (a2 == 123) << endl;

    return 0;
}

这行得通。

但是如果我用模板替换两个operator==(具有相同的正文):

template <bool is_signed>
bool operator==(A<is_signed> lhs, A<is_signed> rhs) {
    return lhs.a_ == rhs.a_;
}

,它的编译产生错误:

prog.cpp: In function ‘int main()’:
prog.cpp:31:14: error: no match for ‘operator==’ (operand types are ‘A<true>’ and ‘int’)
  cout << (a1 == 123) << endl;
           ~~~^~~~~~
prog.cpp:23:6: note: candidate: ‘template<bool is_signed> bool operator==(A<is_signed>, A<is_signed>)’
 bool operator==(A<is_signed> lhs, A<is_signed> rhs) {
      ^~~~~~~~
prog.cpp:23:6: note:   template argument deduction/substitution failed:
prog.cpp:31:17: note:   mismatched types ‘A<is_signed>’ and ‘int’
  cout << (a1 == 123) << endl;
                 ^~~

这里可以使用模板吗?我可以以某种方式使用 C++17 用户定义的模板推导指南吗?还是别的什么?

【问题讨论】:

    标签: c++ templates implicit-conversion template-argument-deduction


    【解决方案1】:

    template argument deduction 中不考虑隐式转换,这会导致 is_signed 的推导在第二个函数参数上失败。

    类型推导不考虑隐式转换(除了上面列出的类型调整):这是overload resolution 的工作,稍后会发生。

    如果您总是以a1 == 123 之类的样式使用operator==,即始终将A&lt;is_signed&gt; 用作第一个操作数,则可以从推导中排除第二个函数参数。例如

    template <bool is_signed>
    bool operator==(A<is_signed> lhs, std::type_identity_t<A<is_signed>> rhs) {
        return lhs.a_ == rhs.a_;
    }
    

    LIVE

    PS:自 C++20 起支持std::type_identity;即使实现一个也不难。

    【讨论】:

    • 也可以反过来添加运算符,但是在比较 As 而不进行隐式比较(例如 another 没有任何std::type_identity_t)。 godbolt.org/z/J39Veq
    【解决方案2】:

    另一种选择是friend函数,所以该函数不是模板,而是使用模板参数:

    template <bool is_signed>
    class A {
    public:
        // implicit conversion from int
        A(int a) : a_{is_signed ? -a : a}
        {}
    
        int a_;
    
        friend bool operator==(const A& lhs, const A& rhs) {
            return lhs.a_ == rhs.a_;
        }
    };
    

    Demo

    【讨论】:

      【解决方案3】:

      模板参数推导不考虑隐式转换。您再次需要两个重载的比较运算符。

      template <bool is_signed>
      bool operator==(A<is_signed> lhs, A<is_signed> rhs) {
          return lhs.a_ == rhs.a_;
      }
      
      template <bool is_signed>
      bool operator==(A<is_signed> lhs, int rhs) {
          return lhs == A<is_signed>(rhs);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多