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?
Yes, this is correct. A type T
is explicitly constructible from an argument A
if
A
. That is, a hypothetical T x(a)
is valid.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With