How is std::is_constructible<T, Args> implemented? [duplicate]
Asked Answered
A

1

9

So far I can't find anything ELI5 online. For a learning project I would like to implement my own is_constructible. Can someone explain how it works, please?

Amylose answered 4/7, 2016 at 9:34 Comment(0)
T
21

From cppreference:

[I]f the variable definition T obj(std::declval<Args>()...); is well-formed, value is equal to true, else value is false.

Checking whether code is well-formed can be done with SFINAE techniques, for example the void_t<> trick (expected to be part of the C++1z standard library):

template <class...>
using void_t = void;

template <class, class T, class... Args>
struct is_constructible_ : std::false_type {};

template <class T, class... Args>
struct is_constructible_<
    void_t<decltype(T(std::declval<Args>()...))>,
T, Args...> : std::true_type {};

template <class T, class... Args>
using is_constructible = is_constructible_<void_t<>, T, Args...>;

The using hoop-hopping is there to place the void_t<> argument first. It usually comes last with a default type, but that position is held by the variadic Args pack.

When is_constructible_ is instantiated for <void, T, Args...>, the compiler tries to instantiate the specialization first. This only succeeds if the contents of void_t<...> are semantically valid, that is, T(std::declval<Args>()...) could be executed correctly -- as specified in the requirements of is_constructible. Note that I have used a temporary instead of a local variable, but to my knowledge the rules don't change between the two. The specialization inherits from std::true_type, which yields a true value.

If the specialization cannot be instantiated (i.e, T(std::declval<Args>()...) is not valid), the compiler falls back to the general template, which can always be instantiated. This one inherits from std::false_type, which yields the false value.

Live on Coliru

More precise traits, such as std::is_trivially_constructible, need more advanced knowledge of the language rules to craft the expression whose validity should become the value of the trait. If this proves infeasible from inside the language, such as with std::is_standard_layout, then the compiler itself has to provide an intrinsic function to retrieve the value.

Toledo answered 4/7, 2016 at 9:53 Comment(3)
This isn't exactly equivalent to std::is_constructible, because T(Arg) is equivalent to a C-style cast - so your is_constructible<intptr_t, int*> is true, while the std one will return false.Dichogamy
Try template <class T, class... Args> struct is_constructible_< void_t<decltype(::new T(std::declval<Args>()...))>, T, Args...> : std::true_type {}; for the specialized template.Stomatology
See boost.org/doc/libs/1_76_0/boost/type_traits/…Stomatology

© 2022 - 2024 — McMap. All rights reserved.