std::type_info
- простой класс, хотя для его заполнения требуется typeinfo
: конструкция компилятора.
Аналогично, исключения являются обычными объектами, но для создания исключений требуется магия компилятора (где выделяются исключения?).
Вопрос для меня: «Как близко мы можем добраться до std::initializer_list
s без магии компилятора?»
Глядя на wikipedia , std::initializer_list<typename T>
может быть инициализирован чем-то, что очень похоже на литерал массива. Давайте попробуем дать нашему std::initializer_list<typename T>
конструктор преобразования, который принимает массив (т.е. конструктор, который принимает один аргумент T[]
):
namespace std {
template<typename T> class initializer_list {
T internal_array[];
public:
initializer_list(T other_array[]) : internal_array(other_array) { };
// ... other methods needed to actually access internal_array
}
}
Аналогично, класс, который использует std::initializer_list
, делает это, объявляя конструктор, который принимает один std::initializer_list
аргумент - a.k.a. конструктор преобразования:
struct my_class {
...
my_class(std::initializer_list<int>) ...
}
Итак, строка:
my_class m = {1, 2, 3};
Заставляет компилятор думать: «Мне нужно вызвать конструктор для my_class
; my_class
имеет конструктор, который принимает std::initializer_list<int>
; У меня есть литерал int[]
; я могу преобразовать int[]
в std::initializer_list<int>
; и я могу передать это конструктору my_class
"( прочитайте до конца ответа, прежде чем сказать мне, что C ++ не позволяет объединять два неявных пользовательских преобразования ).
Так как это близко? Во-первых, мне не хватает нескольких функций / ограничений списков инициализаторов. Одна вещь, которую я не применяю, состоит в том, что списки инициализатора могут быть созданы только с литералами массива, в то время как мой initializer_list
также будет принимать уже созданный массив:
int arry[] = {1, 2, 3};
my_class = arry;
Кроме того, я не стал возиться с ссылками на rvalue.
Наконец, этот класс работает только так, как это говорит новый стандарт, если компилятор неявно объединяет два пользовательских преобразования вместе. Это специально запрещено в обычных случаях, поэтому пример все еще нуждается в магии компилятора. Но я бы сказал, что (1) сам класс является нормальным классом, и (2) задействованная магия (обеспечение синтаксиса инициализации «литерала массива» и возможность неявного связывания двух пользовательских преобразований) меньше, чем кажется первый взгляд.