В C ++ существует правило, согласно которому никакое неявное преобразование не будет использовать два пользовательских преобразования.
Это связано с тем, что такие преобразования на большие расстояния могут привести к чрезвычайно удивительным результатам.
Если вы хотите иметь возможность конвертировать из всего, что может конвертировать в uint8_t
, вы можете сделать:
template<class IntLike,
std::enable_if_t<std::is_convertible_v<IntLike, std::uint8_t>, bool> =true,
std::enable_if_t<!std::is_same_v<A, std::decay_t<IntLike>>, bool> =true
>
A( IntLike&& intlike ):A( static_cast<std::uint8_t>(std::forward<IntLike>(intlike)) )
{}
, или вы можете разыграть B
до uint8_t
в точке, которую вы хотите преобразовать в A
.
Вы можете сделать аналогичную вещь в B
, где вы создаете магический template<class T, /*SFINAE magic*/> operator T
, который превращается во все, что может быть построено с помощью uint8_t
.
Этот неясный код:
std::enable_if_t<std::is_convertible_v<IntLike, std::uint8_t>, bool> =true,
std::enable_if_t<!std::is_same_v<A, std::decay_t<IntLike>>, bool> =true
существует, чтобы убедиться, что перегрузка используется только в том случае, если тип, из которого мы выполняем преобразование, имеет нужные нам свойства.
В первом предложении enable_if
говорится, что нам нужны только вещи, которые можно преобразовать в uint8_t
. Во-вторых, мы не хотим, чтобы этот конструктор использовался для самого типа A
, даже если он проходит первый.
Всякий раз, когда вы создаете неявный конструктор для пересылки ссылок для типа, это второе предложение очень необходимо, или у вас возникают другие неожиданные проблемы.
Используемая техника называется SFINAE или Ошибка замещения не является ошибкой. Когда выводится тип IntType
и эти тесты не выполняются, в этих предложениях возникает ошибка замещения. Обычно это вызывает ошибку, но при оценке перегрузок шаблона это не ошибка, потому что SFINAE; вместо этого он просто блокирует рассмотрение этого шаблона в разрешении перегрузки.