Expected<T>
se implementa en llvm / Support / Error.h. Es una unión etiquetada que tiene una T
o una Error
.
Expected<T>
es una clase de plantilla con tipo T
:
template <class T> class LLVM_NODISCARD Expected
Pero estos dos constructores realmente me confunden:
/// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
/// must be convertible to T.
template <class OtherT>
Expected(Expected<OtherT> &&Other,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
* = nullptr) {
moveConstruct(std::move(Other));
}
/// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
/// isn't convertible to T.
template <class OtherT>
explicit Expected(
Expected<OtherT> &&Other,
typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
nullptr) {
moveConstruct(std::move(Other));
}
¿Por qué Expected<T>
repite dos construcciones para la misma implementación? ¿Por qué no lo hace así?
template <class OtherT>
Expected(Expected<OtherT>&& Other) { moveConstruct(std::move(Other));}
explicit
palabra claveexplicit
palabras clave son importantes aquí. ¿Alguien podría dar un ejemplo?Respuestas:
Porque ese constructor es condicionalmente explícito de acuerdo con la propuesta. Esto significa que el constructor es explícito solo si se cumple alguna condición (aquí, convertibilidad de
T
yOtherT
).C ++ no tiene un mecanismo para esta funcionalidad (algo así como
explicit(condition)
) antes de C ++ 20. Por lo tanto, las implementaciones deben usar algún otro mecanismo, como la definición de dos constructores diferentes , uno explícito y otro de conversión , y garantizar la selección del constructor adecuado de acuerdo con la condición. Esto normalmente se realiza a través de SFINAE con la ayuda destd::enable_if
, donde se resuelve la condición.Desde C ++ 20, debe haber una versión condicional del
explicit
especificador. La implementación sería mucho más fácil con una sola definición:fuente
Para entender esto debemos comenzar con
std::is_convertible
. Según cppreference :La parte importante aquí es que solo busca conversiones implícitas. Por lo tanto, lo que significan las dos implementaciones en su OP es que si
OtherT
es implícitamente convertible aT
, entoncesexpected<OtherT>
es implícitamente convertible aexpected<T>
. SiOtherT
requiere una conversión explícita aT
, entoncesExpected<OtherT>
requiere y una conversión explícita aExpected<T>
.Aquí hay ejemplos de modelos implícitos y explícitos y sus
Expected
homólogos.fuente
Expected<OtherT>
requiere un reparto explícito paraExpected<T>
significar'. ¿Qué significa el "reparto explícito" aquí? No puedo imaginar un ejemplo para esto.