Search code examples
c++c++-concepts

Defining a concept with strict type-checking of method arguments


I have the following:

struct Base {};
struct Derived : public Base {};

struct DualHandler {
  static void handle(Base&) {}
  static void handle(Derived&) {}
};

struct SingleHandler {
  static void handle(Base&) {}
};

I want to define a concept that is satisfied by DualHandler but not by SingleHandler. How can I do this?

My naive attempt is:

template<typename T>
concept IsDualHandler = requires(Base& b, Derived& d) {
     { T::handle(b) };
     { T::handle(d) };
};

But unfortunately, SingleHandler satisfies IsDualHandler, because a Derived& can be passed to any function that expects a Base&.


Solution

  • template<class T>
    struct be_exactly {
      template<class U> requires (std::same_as<std::decay_t<T>,std::decay_t<U>>)
      operator U&();
    };
    

    this tries to match a function argument only exactly.

    template<typename T>
    concept IsDualHandler = requires(be_exactly<Base> b, be_exactly<Derived> d) {
      { T::handle(b) };
      { T::handle(d) };
    };
    

    this distinguishes them.

    Live example.

    I don't like it being references hard coded; you can fix that with way too much boilerplate.