c++stdtemplate-meta-programmingsfinaedeclval

Cannot detect protected base class method with SFINAE


I attempted the following approach using c++ SFINAE and std::declval to find if there exists the proper method in a base class, that can be called from the derived class. The derived class gets the base class from a template parameter. This works for a public method in the base class but not a protected method. Ideally I would prefer to keep the method I'm checking for protected. Here is the simplified code

template <class Base>
class Derived : public Base {

  // SFINAE tester to find existence of foo (only works with public foo methods)
  template <class Type>
  static auto test_foo(int) -> decltype(std::declval<Type>().foo(std::declval<Bar&>()), std::true_  type());
  template <class>
  static auto test_foo(...) -> std::false_type;
  using has_foo = decltype(test_foo<Base>(0));

  // using the has_foo constexpr
  void process_bar(Bar& bar) {
    if constexpr (has_foo{})
      Base::foo(bar);
    ...
  }
};

Is there a way to transform this so that it can access the protected member of the base class while using declval (I think using std::declval<Base> might be making it so that it doesn't have access to the protected members of Base despite inheriting from it). Any help is appreciated, thanks!


Solution

  • So I ended up using Ted Lyngmo's comment for my personal problem, it requires using requires from c++20, if you can't use c++20 maybe try using max66's answer. requires is way less verbose than the decltype testing which although neat is a little ugly and less portable. Here's the code that works for me:

    template <class Base>
    class Derived : public Base {
      // using requires constexpr
      void process_bar(Bar& bar) {
        if constexpr (requires{Base::foo(bar);})
          Base::foo(bar);
        ...
      }
    };