Search code examples
c++c++20type-traitsc++-concepts

C++20: Implement std::is_constructible using concepts


Is there a portable way to implement std::is_constructible using concepts without STL using requires expression or template metaprogramming only?

Consider this code:

template <class T, class... Args>
struct is_constructible
    : std::bool_constant<requires {
      new T(std::declval<Args>()...);
    }> {
};

It works fine for other data types except for references because one can't new a reference type.

// Test cases
auto main() -> int {
  static_assert(is_constructible<int>::value);
  static_assert(is_constructible<int, int>::value);
  static_assert(is_constructible<int, float>::value);
  static_assert(!is_constructible<int, int *>::value);
  static_assert(is_constructible<int &, int &>::value);
  static_assert(is_constructible<int &&, int &&>::value);
  static_assert(!is_constructible<void, void>::value);
  static_assert(!is_constructible<int(), int()>::value);
  static_assert(is_constructible<int (*)(), int()>::value);
  static_assert(!is_constructible<intptr_t, int *>::value);
  static_assert(!is_constructible<int &, float &>::value);

  static_assert(std::is_constructible<int>::value);
  static_assert(std::is_constructible<int, int>::value);
  static_assert(std::is_constructible<int, float>::value);
  static_assert(!std::is_constructible<int, int *>::value);
  static_assert(std::is_constructible<int &, int &>::value);
  static_assert(std::is_constructible<int &&, int &&>::value);
  static_assert(!std::is_constructible<void, void>::value);
  static_assert(!std::is_constructible<int(), int()>::value);
  static_assert(std::is_constructible<int (*)(), int()>::value);
  static_assert(!std::is_constructible<intptr_t, int *>::value);
  static_assert(!std::is_constructible<int &, float &>::value);
  
  return {};
}

Solution

  • No. Certainly not "cleanly and nicely".

    In fact, early proposals during the standardization process attempted to implement constructible_from using requires expressions, but there were so many corner cases that we gave up and specified it in terms of the type trait instead.