user3612643
user3612643

Reputation: 5772

Explicit instantiation for concept checking

We have:

template<typename T>
struct A {
  void foo(int a) {
    T::foo(a);
  }
};

template<typename T> 
struct B {
  template struct A<T>; // concept check
};

So, I define a concept checker A that checks T by forwarding foo to T::foo.

Now, I want to check whether the argument passed to B satisfies the concept A by explicit instantiation, but the compiler complains that it's the wrong namespace. How can I fix that?

Upvotes: 0

Views: 103

Answers (2)

user3612643
user3612643

Reputation: 5772

So, I found a working example:

#include <tuple>

template<typename A>
struct IA : A {
    void foo(int a) {
        A::foo(a);
    }

    void bar(double a) {
        A::bar(a);
    }  

    static constexpr auto $ = std::make_tuple(&IA::foo, &IA::bar);
};

template<typename T> 
struct B {
    // trigger concept/interface check of T "implements" IA
    static constexpr auto $ = IA<T>::$;
};

struct Test {
    void foo(int a) {}
    void bar(int a, int b) {}
};

int main() {
    B<Test> b;
    b = b;
}

The generation of $ in the structs triggers the compilation. The compiler in the example above correctly complains with:

 In instantiation of 'void IA<A>::bar(double) [with A = Test]':
13:57:   required from 'constexpr const std::tuple<void (IA<Test>::*)(int), void (IA<Test>::*)(double)> IA<Test>::$'
18:27:   recursively required from 'constexpr const std::tuple<void (IA<Test>::*)(int), void (IA<Test>::*)(double)> B<Test>::$'
18:27:   required from 'struct B<Test>'
28:13:   required from here
10:17: error: no matching function for call to 'IA<Test>::bar(double&)'
10:17: note: candidate is:
24:10: note: void Test::bar(int, int)
24:10: note:   candidate expects 2 arguments, 1 provided

Upvotes: 0

Igor Tandetnik
Igor Tandetnik

Reputation: 52471

Something like this perhaps:

template<typename T, void(T::*)(int)>
struct A {};

template<typename T> 
struct B {
  using Check = A<T, &T::foo>;
};

Demo


Or this:

template<typename T> 
struct B {
  static_assert(
    std::is_same<decltype(&T::foo), void(T::*)(int)>::value,
    "No T::foo(int) member");
};

Upvotes: 1

Related Questions