如何使用模板函数进行隐式转换

6

这是一个非常简化的例子(忽略类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 functionint main()’:
prog.cpp:31:14: error: no match foroperator==’ (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用户定义的模板类型推导指南?还是有其他方法?

3个回答

6

模板参数推导中不考虑隐式转换,这导致is_signed的推导失败。

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

如果始终以a1 == 123的方式使用operator==,即A<is_signed>始终用作第一个操作数,则可以将第二个函数参数从推导中排除。\例如。

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

直播

PS:自C++20起支持std::type_identity;即使没有很难实现。


也可以反过来添加运算符,但是在比较没有隐式比较(例如没有任何std::type_identity_t的另一个重载)的A时,需要额外的努力来消除歧义。 https://godbolt.org/z/J39Veq - Max Langhof

5

另一种选择是使用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


4

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接