Is there a way to write a concept to check if a type is a structural type

85 views Asked by At

I'm trying to write a concept that checks if a type is a structural type (can be used as non type parameter in a template). Writing one to check if a default constructable type is structural was quite easy but I can't find a way to express the general requirement as it seems that "requires" parameters can't be "declared" as constexpr.

struct StructuralType1 {
  constexpr StructuralType1(int a=42): a(a) {

  }
  int a;
};

struct StructuralType2 {
  constexpr StructuralType2(int a): a(a) {

  }
  int a;
};

struct NonStructuralType {
  constexpr NonStructuralType(int a): a(a) {

  }
private:
  int a;
};

template <auto T> consteval void is_structural_helper() {

};

template<typename T>
concept is_structural = requires () {
  {is_structural_helper<T{}>() }; // T{}
};

// These are ok
static_assert(is_structural<StructuralType1>, "BUG! StructuralType1 is not structural");
static_assert(!is_structural<NonStructuralType>, "BUG! NontStructuralType is structural");

// This fails (StructuralType2 is not default constructable but still is a structural type)
//static_assert(is_structural<StructuralType2>, "BUG! StructuralType2 is not structural");

template <auto X> constexpr int increment() {
  return X.a+1;
}

constexpr int fourtytwo=increment<StructuralType2{41}>();
1

There are 1 answers

0
Ted Lyngmo On

clang++, icx and MSVC accepts this form (and your asserts passes), but unfortunately, gcc doesn't (which thinks even NonStructuralType can be used as a non-type template parameter type). I filed bug #114504 in gcc's bugzilla:

template <typename T>
concept is_structural = requires {
    // try to instantiate a lambda with T as the structural type:
    []<T t> {};
};

Demo