Наследовать конструкторы с переменными аргументами - PullRequest
0 голосов
/ 12 мая 2019

У меня есть простой класс А с двумя конструкторами. Один из них имеет верные параметры. А класс B - это просто производный класс, и я хочу создать экземпляр класса B, используя производные конструкторы из класса A.

Все работает, пока я не захочу использовать особенность вариационных аргументов Последнее утверждение вызывает ошибку компилятора, говоря:

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

Как я могу исправить эту проблему.

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;
}

Вывод будет:

Do something
Do something
Do something else
Do something else
ERROR :(

Ответы [ 3 ]

1 голос
/ 12 мая 2019

Во-первых, я хочу упомянуть, что Вариативные аргументы - это языковая функция C , которая была просто унаследована в C ++ (и сохранена для совместимости).

Современный C ++ предоставляет альтернативы сохранения типа, такие как Пакет параметров , Списки инициализаторов , которые, по-моему, должны быть предпочтительными.

Однако, тем не менее, теперь возможное решение.

Однажды я нашел его, когда попытался имитировать что-то похожее на printf().В то время я заметил существование vprintf() и понял, почему и для чего он хорош.

Это основная идея, я попытался решить дилемму ОП:

#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));
}

Вывод:

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 демо на coliru

Подсказка:

ИМХО общей ловушкой с переменными аргументами являются продвижения аргументов по умолчанию , упомянутое, например, здесь: Вариативные аргументы - преобразования по умолчанию .(Я отметил это с соответствующим комментарием, где это было уместно в моем примере кода.)

1 голос
/ 12 мая 2019

@ Экин: Твоя идея великолепна.Следующий код удовлетворяет всем моим пожеланиям (я просто должен сделать специальный случай для veradic конструктора: 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
};
1 голос
/ 12 мая 2019

Вам необходимо отдельно наследовать функции с переменными аргументами.

[EDIT]

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

Таким образом, вызовы вашего конструктора в main() будут работать без сбоев.

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, ...)

И результат будет:

Do something
Do something
Do something else
Do something else
Do something else
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...