2

I've got a simple class A with two constructors. One of them has veradic parameters. And class B is just the derived class and I want to instantiate class B using the derived constructors from class A.

Everything works until I want to use the special feature of variadic arguments. The last statement provokes an compiler error saying:

"sorry, unimplemented: passing arguments to ellipsis of inherited constructor B::B(int, ...) [inherited from A]".

How can I fix that issue.

class A {
    public:
        A(float f){
            std::cout << "Do something" << std::endl;
        }

        A(int a, ...){
            std::cout << "Do something else" << std::endl;
        }
};

class B : public A {
    using A::A;
};

int main(){

    A a(2.0f); // works
    B b(1.0f); // works

    A c(1, 2, 3); // works
    B d(1); // works
    B e(1, 2); // doesn't work

    return 0;
}

The output would be:

Do something
Do something
Do something else
Do something else
ERROR :(
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Moritz Seppelt
  • 51
  • 1
  • 10

3 Answers3

1

You need to inherit functions with variadic arguments seperately.

[EDIT]

class B : public A {
public:
    using A::A;
    B(int a, int ...) :A(a) {}
};

That way your constructor calls in main() would work flawlessly.

A a(2.0f); // calls A(float f)
B b(1.0f); // calls A(float f)

A c(1, 2, 3); // calls A(int a, ...)
B d(1); // calls A(int a, ...)
B e(1, 2); // calls A(int a, ...)

And the output would be:

Do something
Do something
Do something else
Do something else
Do something else
Ekin Karadağ
  • 51
  • 1
  • 7
1

First, I want to mention that Variadic arguments is a C language feature which just was inherited in C++ (and kept for compability).

Modern C++ provides type save alternatives like Parameter pack, Initializer Lists which IMHO should be preferred.

However, that said, now a possible solution.

I once found it when I tried to mimic something similar like printf(). At that time, I noticed the existance of vprintf() and got why and for what it is good for.

This is the basic idea, I tried to solve the dilemma of OP:

#include <cstdarg>
#include <iostream>

class A {
  public:
    A(float f)
    {
      std::cout << "A::A(" << f << ")\n";
    }

    A(int n, ...)
    {
      std::cout << "A::A(";
      va_list args;
      va_start(args, n);
      getArgs(n, args);
      va_end(args);
      std::cout << ")\n";
    }
  protected:
    A()
    {
      std::cout << "A::A()\n";
    }

    void getArgs(int n, va_list args)
    {
      std::cout << n;
      for (int i = 0; i < n; ++i) {
        float arg = va_arg(args, double); // Please, note, float is not a standard argument type.
        std::cout << ", " << arg;
      }
    }
};

class B: public A {
  public:
    B(float f): A(f)
    {
      std::cout << "in B::B(float)\n";
    }

    B(int n, ...)
    {
      std::cout << "in B::B(";
      va_list args;
      va_start(args, n);
      getArgs(n, args);
      va_end(args);
      std::cout << ")\n";
    }
};

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  std::cout << "Test flavors of A::A():\n";
  DEBUG(A a1(1.23f));
  DEBUG(A a2(3, 1.2f, 2.3f, 3.4f));
  std::cout << "Test flavors of B::B():\n";
  DEBUG(B b1(1.23f));
  DEBUG(B b2(3, 1.2f, 2.3f, 3.4f));
}

Output:

Test flavors of A::A():
A a1(1.23f);
A::A(1.23)
A a2(3, 1.2f, 2.3f, 3.4f);
A::A(3, 1.2, 2.3, 3.4)
Test flavors of B::B():
B b1(1.23f);
A::A(1.23)
in B::B(float)
B b2(3, 1.2f, 2.3f, 3.4f);
A::A()
in B::B(3, 1.2, 2.3, 3.4)

Live Demo on coliru

Hint:

An IMHO common trap with variadic arguments are the default argument promotions, mentioned e.g. here: Variadic arguments – Default conversions. (I remarked this with a resp. comment where it was relevant in my sample code.)

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • All of this was already clear to me. I just didn't want to write the constructor for ever new class deriving from A. But thanks nevertheless – Moritz Seppelt May 12 '19 at 11:42
  • You didn't wast my time :D. Probably I just wasn't clear enough about my issue. And your answer was great for others complaining about similar issues. I am always happy, when someone responds :D – Moritz Seppelt May 12 '19 at 11:48
  • @MoritzSeppelt It's not too late to refine your question. Just use the [edit](https://stackoverflow.com/posts/56098358/edit) link under your question... ;-) – Scheff's Cat May 12 '19 at 11:50
1

@Ekin: Your idea is great. The following code satisfies all my wishes (I just have to make a special case for the veradic constructor :D).

class B : public A {
public:
    using A::A; // Takes care of all normal constructors

    B(int a, int ...) :A(a) {}  // Takes care of the veradic constructor
};
Moritz Seppelt
  • 51
  • 1
  • 10