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?
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.
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 © 2022 - 2024 — McMap. All rights reserved.
std::is_constructible
, becauseT(Arg)
is equivalent to a C-style cast - so youris_constructible<intptr_t, int*>
istrue
, while thestd
one will return false. – Dichogamy