Почему операторы преобразования вызывают неоднозначную перегрузку, когда существуют const-ref и value - PullRequest
0 голосов
/ 12 января 2019

Я смотрю на класс обтекания, основанный на https://www.fluentcpp.com/category/strong-types/ Основное отличие состоит в том, что я заменяю метод get() явным оператором приведения, поскольку это вызывает вопросы во время проверки кода при его использовании.

Как видно из приведенного ниже упрощенного кода, у меня есть 3 перегрузки оператора приведения:

  • От const A & до int
  • С A && до int
  • С const A & до const int &

При написании: static_cast<int>(a) я ожидаю, что будет использоваться перегрузка от const A & до int. Тем не менее, он в равной степени поддерживает перегрузку int и const int &. Почему это так?

Аналогично этому, кажется, разрешено const int &r = static_cast<const int &>(createA());, что, как я полагаю, является пожизненной ошибкой. (при условии, что createA возвращает значение A)


Упрощенный код в обозревателе компиляторов: https://gcc.godbolt.org/z/YMH9Ed

#include <utility>

struct A
{
    int v = 42;
    explicit operator int() const & { return v; } // Removing this line works
    explicit operator int() && { return std::move(v); }
    explicit operator const int &() const & { return v; }
};

int main(int, char**)
{
    A a;
    int r = static_cast<int>(a);
    return r;
}

Ошибка компиляции:

<source>:14:13: error: ambiguous conversion for static_cast from 'A' to 'int'
    int r = static_cast<int>(a);
            ^~~~~~~~~~~~~~~~~~~
<source>:6:14: note: candidate function
    explicit operator int() const & { return v; }
             ^
<source>:8:14: note: candidate function
    explicit operator const int &() const & { return v; }
             ^

1 Ответ

0 голосов
/ 12 января 2019
explicit operator int() const & { return v; }

и

explicit operator const int &() const & { return v; }

одинаково хорошие преобразования. a - это lvalue, поэтому можно вызывать обе функции. a также не const, поэтому обе функции должны будут применить преобразование const к a, поэтому они обе одинаково хороши. Все, что осталось, это "тип возврата", int или const int&, но оба одинаково хороши для создания int из.

Вам нужно избавиться от одного из операторов преобразования или удалить константу от

explicit operator const int &() const & { return v; }

чтобы превратить его в

explicit operator const int &() & { return v; }

так что неконстантные значения дают вам константную ссылку.

...