Avoiding SFINAE's ambiguous access when base and derived classes have variational inheritance chains

Using SFINAE, you can access individual elements of a variation class template. My problem arises when the base class is inherited from the variational class template, and then the derived class is again inherited from the base and from the variational class template (with different template arguments). There is ambiguity as to which chain of inheritance to follow. Is there a way to eliminate the ambiguity?

For instance:

// compile with flag: -std=c++11
#include <type_traits>

struct A { int x; };
struct B { int x; };
struct C { int x; };
struct D { int x; };

template <class ... Params> class Parameter { };

template <class Param, class ... Tail>
class Parameter<Param, Tail ...> : public Param, public Parameter<Tail ...>
{
  public:
    //! Get a parameter
    template <class Param2>
    typename std::enable_if<std::is_same<Param, Param2>::value, int>::type
    getParam() const
    { return Param::x; }

    //! Get a parameter. Delegate false template matches down the Tail... inheritance line (see SFINAE)
    template <class Param2>
    typename std::enable_if<! std::is_same<Param, Param2>::value, int>::type
    getParam() const
    { return Parameter<Tail ...>::template getParam<Param2>(); }
};

class Base : public Parameter<A, B>
{ };

class Derived : public Base, public Parameter<C, D>
{ };

int main(int const argc, char const * argv[])
{
  Base base;
  int a = base.getParam<A>(); // ok
  int b = base.getParam<B>(); // ok

  Derived derived;
  int c0 = derived.getParam<C>(); // error: request for member ‘getParam’ is ambiguous
  int c1 = derived.Derived::getParam<C>();  // error: request for member ‘getParam’ is ambiguous
  int c2 = derived.Parameter<C, D>::getParam<C>(); // ok but syntax overly complex, especially if many params

  int a0 = derived.getParam<A>(); // error: request for member ‘getParam’ is ambiguous
  int a1 = derived.Base::getParam<A>(); // ok, could be acceptable if also worked on Derived
  int a2 = derived.Parameter<A, B>::getParam<A>(); // ok but syntax overly complex and confusing

  return 0;
}

, : 1) , 2) - . , , .

+4
1

getParam, , :

template <class ... Params> class Parameter;

template <class Param>
class Parameter<Param> : public Param
{
public:
    //! Get a parameter
    template <class Param2>
    typename std::enable_if<std::is_same<Param, Param2>::value, int>::type
    getParam() const
    { return Param::x; }
};

template <class Param, class ... Tail>
class Parameter<Param, Tail ...> : public Parameter<Param>, Parameter<Tail...>
{
public:
    using Parameter<Param>::getParam;
    using Parameter<Tail...>::getParam;
};

class Base : public Parameter<A, B> {};

class Derived : public Base, public Parameter<C, D>
{
public:
    using Base::getParam;
    using Parameter<C, D>::getParam;
};
+3

Source: https://habr.com/ru/post/1536906/


All Articles