Хочу подробно объяснить вопрос. Во многих языках со строгой системой типов (, таких как Felix, Ocaml, Haskell ), вы можете определить полиморфный список, составив конструкторы типов. Вот определение Felix:
typedef list[T] = 1 + T * list[T];
typedef list[T] = (1 + T * self) as self;
В Ocaml:
type 'a list = Empty | Cons ('a, 'a list)
В C это рекурсивно, но не полиморфно и не композиционно:
struct int_list { int elt; struct int_list *next; };
В C++ это было бы сделано так, если бы C++ поддерживал рекурсию типов:
struct unit {};
template<typename T>
using list<T> = variant< unit, tuple<T, list<T>> >;
при наличии подходящего определения для кортежа (также известная как пара )и вариант (, но не сломанный, используемый в Boost ). В качестве альтернативы:
using list<T> = variant< unit, tuple<T, &list<T>> >;
может быть приемлемым, учитывая несколько иное определение варианта.Невозможно было написать это даже на C++ < C++11, потому что без шаблонных определений типов невозможно получить полиморфизм, а без нормального синтаксиса для определения типов невозможно получить целевой тип в области видимости. Приведенный выше синтаксис using решает обе эти проблемы, однако это не означает, что рекурсия разрешена.
В частности, обратите внимание, что разрешение рекурсии сильно влияет на ABI, то есть на изменение имени (это невозможно сделать, если схема изменения имени не допускает представления фиксированных точек ).
Мой вопрос :необходим для работы на C++11? [Предполагая, что расширение не приводит к бесконечно большой структуре]
Изменить :просто для ясности, требуется общая структурная типизация. Шаблоны предусматривают именно то, что, например
pair<int, double>
pair<int, pair <long, double> >
анонимно (структурно )типизированы, а пара явно полиморфна. Однако рекурсия в C++ < C++11 не может быть указана даже с помощью указателя. В С++ 11 вы можете указать рекурсию, хотя с шаблоном typedef (с новым синтаксисом using выражение в левой части знака = находится в области действия в правой части ).
Структурная (анонимная )типизация с полиморфизмом и рекурсией являются минимальными требованиями к системе типов.
Любая современная система типов должна поддерживать функторы полиномиальных типов, в противном случае система типов слишком громоздка для любого вида программирования высокого уровня. Комбинаторы, необходимые для этого, обычно указываются теоретиками типов, такими как :
1 | * | + | fix
, где 1 — единичный тип, *— формирование кортежа, + — формирование варианта, а fix — рекурсия. Идея состоит в том, что:
если t является типом и u является типом, то t + u и t *u также являются типами
В C++ struct unit{} равно 1, tuple равно *, Вариант равен +, и точки фиксации могут быть получены с использованием синтаксиса =. Это не совсем анонимная типизация, потому что для fixpoint потребуется определение типа шаблона.
Изменить :Просто пример конструктора полиморфных типов в C:
T* // pointer formation
T (*)(U) // one argument function type
T[2] // array
К сожалению, в C значения функций не являются композиционными, и формирование указателя зависит от ограничения lvalue, а синтаксические правила для композиции типов сами по себе не являются композиционными, но здесь мы можем сказать :
if T is a type T* is a type
if T and U are types, T (*)(U) is a type
if T is a type T[2] is a type
, чтобы эти конструкторы типов (комбинаторы )можно было применять рекурсивно для получения новых типов без необходимости создавать новый промежуточный тип. В C++ мы можем легко исправить синтаксическую проблему :
template<typename T> using ptr<T> = T*;
template<typename T, typename U> using fun<T,U> = T (*)(U);
template<typename T> using arr2<T> = T[2];
, так что теперь вы можете писать :
arr2<fun<double, ptr<int>>>
, а синтаксис композиционный, как и типизация.