Home > Blockchain >  Why need to forward constructor parameters when inheriting from variadic arguments?
Why need to forward constructor parameters when inheriting from variadic arguments?

Time:11-20

I know the title makes exactly 0 sense, I am challenging you to edit it according to the question.
I have the following wrapper that wraps lambda expressions (inherits from them) and uses their operator()'s for overloading.

#include <iostream>

template<typename... F>
struct OverloadSet : public F...
{
    OverloadSet(F&&... f) : F(std::forward<F>(f))...{}
    using F::operator() ...;
};

template<typename... T>
auto overloads(T...t) {
    return OverloadSet<T...>(std::forward<T>(t)...);
}

auto s = overloads(
    [](int s) {std::cout << typeid(s).name() << " " << s << std::endl; },
    [](double d) {std::cout << typeid(d).name() << " " << d << std::endl; }
);
int main() 
{
    auto s = overloads(
        [](int s) {std::cout<<typeid(s).name()<<" " << s << std::endl; },
        [](double d) {std::cout << typeid(d).name() << " "<< d << std::endl; }
    );
    s(3);
    s(3.2);
}

The code is copied from C design patterns book (highly recommend)

And I have made my observation that the constructor params are redundant as we only need operator()'s of base classes.
So I made the exact example but with more modest constructor:

OverloadSet(F&&... f) {}

From this point I have problems to understand whether this program is ill formed or not because have different reaction from different compilers:

GCC 11.2

Output of x86-64 gcc 11.2 (Compiler #1)
In instantiation of 'OverloadSet<F>::OverloadSet(F&& ...) [with F = {<lambda(int)>, <lambda(double)>}]':
required from 'auto overloads(T ...) [with T = {<lambda(int)>, <lambda(double)>}]'
required from here
error: use of deleted function '<lambda(int)>::<lambda>()'

Clang (latest)

error: constructor for 'OverloadSet<(lambda at <source>:16:2),
 (lambda at <source>:17:2)>' must explicitly initialize the base class '(lambda at <source>:16:2)' which does not have a default constructor
            OverloadSet(F&&... f) {}// F(std::forward<F>(f))...{}

MSVC2019 (with C 20 enabled)

Compiles and prints:
int 3
double 3.2

So the questions are:

  1. Whether the program is well formed?
  2. If not, why do we need to forward arguments if we only use operator()'s of base classes?

CodePudding user response:

The lambda does not have a default constructor, I guess.

It is more like this:

class A {
  public:
    A(int a) {}
};

class B {
  public:
    B(double b) {}
};

class C : public A, public B {
  public:
    C() {} // error
};
  • Related