C++ - How to introduce overload set from variadic

2019-08-07 12:35发布

问题:

The derived class hides the name of an overload set from the base class if the derived class has the same name defined, but we can always introduce that overload set back with using-declaration:

template <class BASE>
class A : public BASE
{
public:
  using BASE::some_method;
  void some_method();
}

But what if I introduce all overload sets from variadic base classes? Would I be able to write something like this?

template <class... BASES>
class A : public BASES...
{
public:
  using BASES::some_method...;
  void some_method();
}

I've considered using a helper class like:

template <class... BASES>
struct helper;

template <>
struct helper<> {};

template <class OnlyBase>
struct helper<OnlyBase> : OnlyBase
{
  using OnlyBase::some_method;
};

template <class Base1, class... OtherBases>
struct helper<Base1, OtherBases> : public Base1, public helper<OtherBases...>
{
  using Base1::some_method;
  using helper<OtherBases...>::some_method;
};

And it does work. But it requires a lot of typing (of course I can use macro but I try to use c++'s compile-time feature whenever possible), and when I want to introduce more methods, i have to change much in that piece of code.

A perfect answer would be a simple syntax, but if there's none, I will go with the helper class.

回答1:

Here is a trick how to reduce handwriting:

// U<X,Y> is a binary operation on two classes
template<template<class,class>class U, class... Xs> struct foldr;
template<template<class,class>class U, class X> struct foldr<U,X> : X {};
template<template<class,class>class U, class X, class... Xs> struct foldr<U,X,Xs...> : U<X, foldr<U,Xs...>> {};

// our operation inherits from both classes and declares using the member f of them    
template<class X, class Y> struct using_f : X,Y { using X::f; using Y::f; };

struct A { void f(int) {} };
struct B { void f(char) {} };
struct C { void f(long) {} };

struct D : foldr<using_f, A, B, C> {};


int main() {
    D d;
    d.f(1);
    d.f('1');
    d.f(1L);
    return 0;
}

So we should write foldr once, then write simple ad-hoc operations - using_f, using_g, using_f_g

Maybe there is a way to further simplifying. Let me think a bit...