Как использовать функцию шаблона для неявного преобразования - PullRequest
6 голосов
/ 22 октября 2019

Очень упрощенный пример (неважно, что делают класс 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? Или что-нибудь еще?

Ответы [ 3 ]

4 голосов
/ 22 октября 2019

Вывод аргумента шаблона не учитывает неявные преобразования. Вам снова нужны два перегруженных оператора сравнения.

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);
}
4 голосов
/ 22 октября 2019

Другой альтернативой является 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_;
    }
};

Демо

4 голосов
/ 22 октября 2019

Неявные преобразования не учитываются в выводе аргумента шаблона , что вызывает сбой при is_signed сбое для второго аргумента функции.

При выводе типа не учитываются неявные преобразования(кроме корректировок типа, перечисленных выше): это работа для разрешения перегрузки , которое происходит позже.

Если вы всегда используете operator== в стиле, подобном a1 == 123т. е. A<is_signed> всегда используется в качестве 1-го операнда, вы можете исключить 2-й функциональный параметр из вычета. например,

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: std::type_identity поддерживается начиная с C ++ 20;даже это не сложно реализовать.

...