Я копирую комментарий, который я сделал, чтобы ответить на этот комментарий в другом месте.
Вы можете понижать с static_cast
. Не так с implicit_cast
. static_cast
в основном позволяет вам выполнять любое неявное преобразование и, в дополнение к этому, обратное преобразование любого неявного преобразования (до некоторых пределов. Вы не можете снизить рейтинг, если задействован виртуальный базовый класс). Но implicit_cast
будет только принимать неявные преобразования. нет приведения вниз, нет void*->T*
, нет U->T
, если T имеет только явные конструкторы для U.
Обратите внимание, что важно отметить разницу между приведением и преобразованием. В последующем не происходит кастинг
int a = 3.4;
Но неявное преобразование происходит из double в int. Такие вещи, как «неявное приведение» не существуют, поскольку приведение всегда является явным запросом преобразования. Конструкция имени для boost::implicit_cast
представляет собой прекрасную комбинацию «преобразования с использованием неявных преобразований». Теперь вся реализация boost::implicit_cast
такова (объяснено здесь ):
template<typename T> struct identity { typedef T type; };
template<typename Dst> Dst implicit_cast(typename identity<Dst>::type t)
{ return t; }
Идея состоит в том, чтобы использовать недетерминированный контекст для параметра t
. Это позволит избежать ловушек, подобных следующим:
call_const_version(implicit_cast(this)); // oops, wrong!
Хотелось написать вот так
call_const_version(implicit_cast<MyClass const*>(this)); // right!
Компилятор не может определить, какой тип должен указывать параметр шаблона Dst
, потому что сначала он должен знать, что такое identity<Dst>
, поскольку он является частью параметра, используемого для вывода. Но это, в свою очередь, зависит от параметра Dst
(identity
может быть явно специализирован для некоторых типов). Теперь у нас есть циклическая зависимость, для которой в стандарте просто говорится, что такой параметр является не выводимым контекстом, и необходимо предоставить явный аргумент шаблона.