Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.133.147.87] |
|
Сообщ.
#1
,
|
|
|
Допустим, имеем некие классы a и b, которые имеют явные конструкторы с разным набором параметров. Пусть будет так:
class a { public: a(int param_1); } class b { public: b(int param_1, int param_2); } теперь я хочу написать шаблон класса c, который будет инстанцироваться этими классами и будет от них наследоваться: template <typename T> class c : public T { public: c (????)' : T(????) {} } Т.е. я хочу делать так: c<a> Ca(1); c<b> Cb(2,3); Это вообще возможно? Параметры конструктора в общем случае очень разных типов (указатели на разные типы, целые числа и т.п.), т.е. привести все конструкторы базовых классов к одинаковому виду путем добавления фиктивных параметров ну очень не хотелось бы, страдает мое чувство прекрасного. И делать свой шаблон под каждый тип параметра тоже не хотелось бы - вся реализация шаблона для разных классов отличается только этой передачей парметров конструктору базового класса. Единственное, что приходит в голову - воткнуть в шаблон конструкторы для всех возможных параметров, но как-то это тоже некрасиво. Может несколько сумбурно изложил, не пинайте, готов ответить на уточняющие вопросы. |
Сообщ.
#2
,
|
|
|
template <typename T> class c : public T { using T::T; /* ... */ }; Добавлено P.S. Т.н. наследование конструкторов. |
Сообщ.
#3
,
|
|
|
Не знаю, не пробовал. Решение красивое. А если мне надо в конструкторе сделать что-то еще? Например, проинициализировать поля класса c?
|
Сообщ.
#4
,
|
|
|
Может быть как то так?
#include <iostream> class SomeA { public: SomeA(int param1) { std::cout << "SomeA: " << param1 << std::endl; } }; class SomeB { public: SomeB(int p1, int p2) { std::cout << "SomeB: " << p1 << " "<< p2 << std::endl; } }; class SomeC { public: SomeC(int p1, int p2, bool p3) { std::cout << "SomeC: " << p1 << " " << p2 << " " << p3 << std::endl; } }; template<class T> class X : public T { public: template<class...U> X(U... args) : T(args...) { } }; int main() { X<SomeC> c(1, 2, false); return 0; } https://ideone.com/7dc9gF Я не силен в вариадиках, но такой вариант вроде как работает. Возможно есть какие то грабли.... |
Сообщ.
#5
,
|
|
|
Wound, спасибо! То, что нужно! Придется мне тоже учить вариадики.
|
Сообщ.
#6
,
|
|
|
Наследование конструкторов появилось в C++11. Немного неправильно его так называть, но называют так. Фактически сия конструкция только переносит сигнатуры конструкторов базового класса в производный. Их действие ограничивается только вызовом соответствующих "базовых" конструкторов, при этом остальные поля конструируются по умолчанию. Если это не устраивает, можно дополнительно воспользоваться другой фичей: делегацией конструкторов.
template <typename T> class c : public T { using T::T; public: template <typename ...Args> c(Args&& ...args): c(std::forward<Args>(args)...) {}; /* ... */ }; |
Сообщ.
#7
,
|
|
|
И если не будет слишком большой наглостью с моей стороны, как добавить к конструктору X дополнительные аргументы? Вот так работает:
template<class...U> X(int p4, U... args) : T(args...) { std::cout << "X: " << p4 << std::endl; } |
Сообщ.
#8
,
|
|
|
Цитата Dushevny @ Это возможно... но я бы пока не советовал. Сложно без практики будет разобраться. Могу намекнуть на sizeof...() и std::tuple<>. хотелось бы дополнительные аргументы добавить в конец |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ Понял. Тогда, действительно, пока не стОит. Это возможно... но я бы пока не советовал |
Сообщ.
#10
,
|
|
|
Приветствую всех снова. Все было просто замечательно, пока мне не потребовалось передать в конструктор ссылку на массив из N элементов. Конструктор шаблона неявно преобразует имя массмва в указатель на первый элемент, а потом компилятор ругается, что у базового класса нет конструктора с таким указателем.
#include <utility> using param = int volatile[2]; class a { public: a(param &) {}; }; class b : public a { public: template <typename ...Args> b(Args ...args) : a(std::forward<Args>(args)...) {} }; param P = {1, 2}; a A(P); b B(P); test.cpp: In instantiation of 'b::b(Args ...) [with Args = {volatile int*}]': test.cpp:21:6: required from here test.cpp:15:36: error: no matching function for call to 'a::a(volatile int*)' 15 | : a(std::forward<Args>(args)...) | ^ test.cpp:7:5: note: candidate: 'a::a(volatile int (&)[2])' 7 | a(param &) {}; | ^ test.cpp:7:7: note: no known conversion for argument 1 from 'volatile int*' to 'volatile int (&)[2]' 7 | a(param &) {}; | ^~~~~~~ test.cpp:4:7: note: candidate: 'constexpr a::a(const a&)' 4 | class a | ^ test.cpp:4:7: note: no known conversion for argument 1 from 'volatile int*' to 'const a&' test.cpp:4:7: note: candidate: 'constexpr a::a(a&&)' test.cpp:4:7: note: no known conversion for argument 1 from 'volatile int*' to 'a&&' Не хочу переписывать конструктор базового класса на указатель, потому что тогда можно будет передавать массив из произвольного количества элементов, а я хочу получать от компилятора по рукам, если количесво элементов в массиве отличается от N. Что посоветуете? Может можно каким-нибудь std::что_то<param &>(P) запретить неявное преобразование к указателю? |
Сообщ.
#11
,
|
|
|
Ты где-то потерял универсальную ссылку:
template <typename ...Args> b(Args&& ...args) : a(std::forward<Args>(args)...) {} P.S. К указателям не сводятся ссылки, а использование в шаблонах универсальных ссылок совместно с форвардом восстанавливает исходный тип в точности. Принимая же параметры по значению вместо ссылки, ты разрешаешь компилятору выполнить сведение, что он и делает, сводя массив к указателю, т.к. массивы по значению передавать нельзя. |
Сообщ.
#12
,
|
|
|
Цитата Qraizer @ "Семен Семеныч!" Это я пример от Wound взял. Спасибо! Ты где-то потерял универсальную ссылку: |