3

Is there a way to overload/specialize concepts like templates?

Consider the following pretty simple case where we just want to flag certain Types as 'simple':

// overload/specialization for MyClass - WOULD BE NICE - BUT FAILS

template <typename T>
concept simple = false;

class MyClass;
template <>
concept simple<MyClass> = true;

// workaround, rather verbose - SUCCEEDS

template <typename T>
concept simple = Info<T>::is_simple;

template <typename T>
struct Info
{
    static inline constexpr bool is_simple = false;
};    

class MyClass;
template <>
struct Info<MyClass>
{
    static inline constexpr bool is_simple = true;
};

Is there a simpler way to achieve this?

non-user38741
  • 671
  • 5
  • 19

1 Answers1

2

Is there a way to overload/specialize concepts like templates?

No. You cannot overload or specialize concepts. Concepts are what they are. This is by design.

If I have a concept Frobnable, that concept always means what it means. The fundamental issue with template specializations is that that the specializations don't actually have to have anything to do with the primary. We just like... ensure that they are, for sanity's sake. Except when we don't, like vector<bool> doesn't really have the same interface as vector<T> for all other T.

But if Frobnable<T> meant something just totally different from Frobnable<T*> (or insert your choice of specialization here), then you couldn't possibly come up with any rules for what concept subsumption would mean - or really reason about concepts much at all.

Concepts are much more structured than templates.


So to go back to your question of how do

[...] we just want to flag certain Types as 'simple':

You should use a variable template for this, and then possibly have a concept just refer to that variable template.

template <typename T>
inline constexpr bool is_simple = false;

template <>
inline constexpr bool is_simple<MyClass> = true;

template <typename T>
concept simple = is_simple<T>::value;

Or don't even bother with the concept and just use the variable template directly in a requires clause.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • That's the shorter workaround, however it's problematic when a class in a namespace wants to declare itself as 'simple'. That's why I used the Info wrapper class. – non-user38741 Aug 12 '20 at 19:31
  • concept is actually worth it to bother with: `void foo(simple auto x)` – Daniel Aug 12 '20 at 19:33
  • 1
    @non-user38741 Sorry, what's problematic? The variable template is definitely shorter than the class template, and will compile faster. – Barry Aug 12 '20 at 19:34
  • (At least) MSVC complains with C2888 if the specialization is in some namespace while the general template is in the global namespace. Note that i want the user of my lib to specify whether his type is considered as simple. So they will typically be in a user namespace. – non-user38741 Aug 12 '20 at 19:41
  • @non-user38741 Oh, well yeah - the specialization has to be the variable template's namespace. That's just the rule. – Barry Aug 12 '20 at 19:54