Явные ref-квалифицированные шаблоны операторов преобразования в действии

Учитывая следующие операторы преобразования

struct A
{
template<typename T> explicit operator T&&       () &&;
template<typename T> explicit operator T&        () &;
template<typename T> explicit operator const T&  () const&;
};

struct B {};

Я ожидаю, что следующие преобразования будут действительными, но некоторые из них дают ошибки компиляции (живой пример):

A a;

A&&      ar = std::move(a);
A&       al = a;
const A& ac = a;

B&&      bm(std::move(a));  // 1. OK
B&&      bt(A{});           // 2. OK
B&&      br(ar);            // 3. error: no viable conversion from A to B
B&       bl(al);            // 4. OK
const B& bz(al);            // 5. OK
const B& bc(ac);            // 6. OK

B        cm(std::move(a));  // 7. error: call to constructor of B ambiguous
B        ct(A{});           // 8. error: call to constructor of B ambiguous
B        cr(ar);            // 9. OK

В частности, 1, кажется, идентичен 3 и почти идентичен 2 (аналогично для 7-9, 8), но ведет себя по-разному.

Любое объяснение или обходной путь?

Моя мотивация Еще один «любой», где мне в итоге пришлось сделать все операторы преобразования explicit чтобы избежать проблем с чертами типа std::is_constructible, std::is_convertibleТогда я столкнулся с новыми проблемами.

РЕДАКТИРОВАТЬ Извините, пожалуйста, игнорируйте 3 и 9, моя ошибка (спасибо Kerrek SB). Тем не менее, 7 и 8 остаются проблемами. Также, explicit кажется, в конце концов не имеет значения, еще раз извините.

РЕДАКТИРОВАТЬ 2 Просто заметил что

B        cm = std::move(a);
B        ct = A{};

действительны, если операторы преобразования не explicit, Так вот где explicit приходит: первоначально мои образцы использовали инициализацию копирования, а когда я переключился на explicit Мне пришлось использовать прямую инициализацию. затем эта проблема возникла (случаи 7 и 8).

8

Решение

Все же 7 и 8 остаются как проблемы

B        cm(std::move(a));  // 7. error: call to constructor of B ambiguous
B        ct(A{});           // 8. error: call to constructor of B ambiguous

Два случая одинаковы: прямая инициализация с аргументом rvalue типа A.

Все функции-кандидаты для прямой инициализации являются конструкторами, и в этом случае оба являются конструктором копирования. B::B(const B&) и переместить конструктор B(B&&) жизнеспособны, так как существует неявное преобразование из значения А в оба const B& и к B&&, Разрешение перегрузки не может определиться между этими двумя конструкторами, потому что для вызова любого из них требуется пользовательское преобразование непосредственно в тип параметра, а пользовательские последовательности преобразования ранжируются только второе стандартное преобразование:

13.3.3.2/3[over.ics.rank]Пользовательская последовательность преобразования U1 является лучшей последовательностью преобразования, чем другая пользовательская последовательность преобразования U2, если они содержат одну и ту же пользовательскую функцию преобразования … и вторая стандартная последовательность преобразования U1 лучше, чем вторая стандартная последовательность преобразования U2 «.

Это отличается от вызова функции-члена, которая имеет && и конст &перегрузки, потому что в этом случае разрешение перегрузки ранжирует привязки ссылок из аргумента rvalue, чтобы повлиять на параметр объекта в соответствии с

Стандартная последовательность преобразования S1 является лучшей последовательностью преобразования, чем стандартная последовательность преобразования S2, если S1 и S2 являются ссылочными привязками (8.5.3) и ни одна из них не ссылается на неявный параметр объекта нестатической функции-члена, объявленной без квалификатора ref, и S1 привязывает ссылку rvalue к значению rvalue, а S2 привязывает ссылку lvalue.

4

Другие решения


По вопросам рекламы [email protected]