Std :: is_constructible does not give the correct result

Derived from this CodeReview Theme:

#include <cstddef> #include <algorithm> #include <iostream> #include <type_traits> #include <utility> template <typename T> class aggregate_wrapper : public T { private: using base = T; public: using aggregate_type = T; template <typename... Ts> aggregate_wrapper(Ts&&... xs) : base{std::forward<Ts>(xs)...} { // nop } }; struct foo_t { foo_t(int) {} }; int main() { std::cout << std::is_constructible<foo_t>::value << std::endl; std::cout << std::is_constructible<aggregate_wrapper<foo_t>>::value << std::endl; // aggregate_wrapper<foo_t> v; // won't compile } 

How does std::is_constructible<aggregate_wrapper<foo_t>>::value be true if aggregate_wrapper<foo_t> v; doesn't actually compile?

+7
c ++ language-lawyer typetraits template-meta-programming c ++ 14
source share
1 answer

In the C ++ standard, the description of is_constructible has this innocent looking quote:

Only the reliability of the immediate context of the initialization of the variable [imaginary v ] is considered.

And then a note explaining what this means:

Initialization evaluation can lead to such as creating instances of specialized class templates and specialized function templates, generating implicitly defined functions, etc. Such side effects are not in the immediate context and can lead to a bad form of the program.

My interpretation is that when you write:

 aggregate_wrapper<foo_t> v; 

You use the default constructor aggregate_wrapper , it exists and is available, so it succeeds, at least in the immediate context. Then the non-femoral context includes the constructor body, and this fails, but this does not change the result of is_constructible .

+2
source share

All Articles