Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if type is explicitly/implicitly constructible?

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?

like image 843
Constructor Avatar asked Mar 14 '17 12:03

Constructor


1 Answers

Yes, this is correct. A type T is explicitly constructible from an argument A if

  1. It is constructible at all from A. That is, a hypothetical T x(a) is valid.
  2. 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.

like image 75
Barry Avatar answered Oct 18 '22 23:10

Barry