2) Существуют ли какие-либо технические причины, по которым вы могли бы помешать «идеальным конструкторам пересылки» стать адекватной альтернативой?
Я показал одну проблему с этим идеальным подходом пересылки: Пересылка всех конструкторов в C ++ 0x .
Кроме того, идеальный подход пересылки не может «пересылать» явность конструкторов базового класса: либо это всегда конструктор преобразования, либо никогда, и базовый класс всегда будет инициализироваться напрямую (всегда с использованием всех конструкторов). даже явные).
Другая проблема - конструкторы списка инициализаторов, потому что вы не можете вывести Args
в initializer_list<U>
. Вместо этого вам нужно переместиться на базу с помощью B{args...}
(обратите внимание на фигурные скобки) и инициализировать D
объекты с (a, b, c)
или {1, 2, 3}
или = {1, 2, 3}
. В этом случае Args
будет типом элементов списка инициализатора и перенаправит их в базовый класс. Затем конструктор списка инициализаторов может их получить. Кажется, это вызывает ненужное раздувание кода, потому что пакет аргументов шаблона может содержать много последовательностей типов для каждой различной комбинации типов и длины, а также потому, что вы должны выбрать синтаксис инициализации, это означает:
struct MyList {
// initializes by initializer list
MyList(std::initializer_list<Data> list);
// initializes with size copies of def
MyList(std::size_t size, Data def = Data());
};
MyList m{3, 1}; // data: [3, 1]
MyList m(3, 1); // data: [1, 1, 1]
// either you use { args ... } and support initializer lists or
// you use (args...) and won't
struct MyDerivedList : MyList {
template<class ... Args>
MyDerivedList(Args&& ... args) : MyList{ args... } { }
};
MyDerivedList m{3, 1}; // data: [3, 1]
MyDerivedList m(3, 1); // data: [3, 1] (!!)