0

I recently saw this in production code and couldn't quite figure out what it does:

template <class... Ts>
struct pool : pool_type<Ts>... {
//...
};

I've never seen pack expansion happening for parent classes. Does it just inherit every type passed into the varargs?

The parents look like this:

template <class T>
struct pool_type : pool_type_impl<T> {
// ...
};
glades
  • 3,778
  • 1
  • 12
  • 34
  • 2
    "*Does it just inherit every type passed into the varargs?*" Yes. – 康桓瑋 Mar 26 '22 at 11:12
  • It is often useful to try things out and see what happens. Put some classes in the list and see if they are base classes. Also works for lambda functions since they are really class objects. – QuentinUK Mar 26 '22 at 11:14
  • 3
    *"Does it just inherit every type passed into the varargs?"* You probably meant the correct thing, but as stated this is not entirely correct. The classes inherited from are `pool_type`s each of the template parameters of `pool` passed as template parameter to `pool_type`, i.e. `pool` has parent classes `pool_type`, `pool_type` and `pool_type`. – fabian Mar 26 '22 at 11:52

1 Answers1

2

Does it just inherit every type passed into the varargs?

Yes. It inherits publicly from each of the passed arguments. A simplified version is given below.

From Parameter pack's documentation:

Depending on where the expansion takes place, the resulting comma-separated list is a different kind of list: function parameter list, member initializer list, attribute list, etc. The following is the list of all allowed contexts:

  • Base specifiers and member initializer lists:
    A pack expansion may designate the list of base classes in a class declaration.

Example

struct Person 
{
    Person() = default;
    Person(const Person&)
    {
        std::cout<<"copy constrcutor person called"<<std::endl;
    }
};
struct Name 
{
    Name() = default;
    Name(const Name&)
    {
        std::cout<<"copy constructor Name called"<<std::endl;
    }
};

template<class... Mixins>
//---------------vvvvvvvvv---------->used as list of base classes from which X inherits publicly
class X : public Mixins...
{
public:
//-------------------------------vvvvvvvvvvvvvvvvv---->used as member initializer list
    X(const Mixins&... mixins) : Mixins(mixins)... {}
};
int main()
{
    Person p;
    Name n;
    X<Person, Name> x(p, n); //or even just X x(p, n);  works with C++17 due to CTAD
    return 0;
}

The output of the above program can be seen here:

copy constrcutor person called
copy constructor Name called
constructor called

Explanation

In the above code, the X class template uses a pack expansion to take each of the supplied mixins and expand it into a public base class. In other words, we get a list of base classes from which X inherits publicly. Moreover, we also have a X constructor that copy-initializes each of the mixins from supplied constructor arguments.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Ok but how would I instantiate it? X x(1,2.3, "hello") where arguments to the X-constructor are copied over to the respective constructors of the base class objects? And why not move them right away? – glades Mar 26 '22 at 12:52
  • 1
    @glades [Here](https://onlinegdb.com/LuIUtY2dh) is a live demo showing how to instantiate it. **In the linked demo you'll notice that the copy constructor is called for each of the passed arguments**.The example that i gave in my answer is just an example from [cppreference](https://en.cppreference.com/w/cpp/language/parameter_pack#Expansion_loci) in which i've added some explanation so that the concept would be more clear to you. For how you can instantiate it and use it in real life, see [here](https://stackoverflow.com/questions/2459987/mixins-variadic-templates-and-crtp-in-c). – Jason Mar 26 '22 at 13:15