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?
1 Answers
From cppreference:
[I]f the variable definition
T obj(std::declval<Args>()...);
is well-formed,value
is equal totrue
, elsevalue
isfalse
.
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
.
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.

- 27,591
- 48
- 66
- 103

- 62,093
- 7
- 131
- 191
-
3This isn't exactly equivalent to `std::is_constructible`, because `T(Arg)` is equivalent to a C-style cast - so your `is_constructible
` is `true`, while the `std` one will return false. – T.C. Nov 05 '16 at 18:43 -
Try `template
struct is_constructible_< void_t – Jeremiah van Oosten May 19 '21 at 22:22()...))>, T, Args...> : std::true_type {}; ` for the specialized template. -
See https://www.boost.org/doc/libs/1_76_0/boost/type_traits/is_constructible.hpp – Jeremiah van Oosten May 19 '21 at 22:26