问题
How can it be checked that some type is explicitly (or vice versa implicitly) constructible from other type? Is it any SFINAE trick in this situation?
I can write is_explicitly_constructible
as a combination of std::is_constructible and std::is_convertible:
#include <type_traits>
template <typename Type, typename Argument>
struct is_explicitly_constructible
: std::bool_constant
<
std::is_constructible<Type, Argument>::value &&
!std::is_convertible<Argument, Type>::value
>
{
};
But do I take into account all possible cases in such code?
回答1:
Yes, this is correct. A type T
is explicitly constructible from an argument A
if
- It is constructible at all from
A
. That is, a hypotheticalT x(a)
is valid. - Implicit conversions are ill-formed. That is, the hypothetical function
T test() { return a; }
would be ill-formed.
std::is_constructible
tests #1, and std::is_convertible
tests the validity of #2. Hence, wanting #1 and not #2 would be is_explicitly_constructible
just as #1 and #2 would be is_implicitly_constructible
.
Such an is_explicitly_constructible
/is_implicitly_constructible
pair is how you would implement a constructor being conditionally explicit
. For instance, in libstdc++, these two constructors for optional
exist:
implicit:
template <typename _Up = _Tp,
enable_if_t<__and_<
__not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>, // (*)
is_convertible<_Up&&, _Tp> // (*)
>::value, bool> = true>
constexpr optional(_Up&& __t)
explicit:
template <typename _Up = _Tp,
enable_if_t<__and_<
__not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>, // (*)
__not_<is_convertible<_Up&&, _Tp>> // (*)
>::value, bool> = false>
explicit constexpr optional(_Up&& __t);
You can see that libstdc++ uses the same expressions that you do.
来源:https://stackoverflow.com/questions/42786565/how-to-check-if-type-is-explicitly-implicitly-constructible