Ограничения, применяемые к параметрам универсальных типов (C++/CLI)

В объявлениях универсального типа или метода можно указать параметр типа с ограничениями. Ограничение — это требование, которому должны удовлетворять типы, используемые в качестве аргументов типа. Например, ограничение может требовать, чтобы аргумент типа реализовывал определенный интерфейс или наследовался от определенного класса.

Ограничения не являются обязательными; отсутствие ограничения на параметр эквивалентно ограничению этого параметра в Object.

where type-parameter: constraint list

Параметры

  • параметр типа (type parameter).
    Один из ограниченных параметров типа.

  • список ограничений
    список ограничений — это разделенный запятыми список спецификаций ограничений. Список может содержать интерфейсы, которые должны быть реализованы параметром типа.

    Список также может содержать класс. Чтобы аргумент типа удовлетворял ограничению базового класса, он должен быть тем же классом, что и указанный в ограничении, либо производным от него.

    Можно также указать gcnew(), чтобы указать, что аргумент типа должен иметь открытый конструктор без параметров, или ref class, чтобы указать, что аргумент типа должен быть ссылочным типом, включая любой класс, интерфейс, делегат или массив; или value class, чтобы указать, что аргумент типа должен быть типом значения. Допускается указание любого типа значения, кроме Nullable<T>.

    Можно также указать универсальный параметр в качестве ограничения. Аргумент типа, предоставленный для ограничиваемого типа, должен быть этим типом либо наследоваться о него. Это называется открытым ограничением типа.

Заметки

Оператор ограничения состоит из where, за которым следует параметр типа, двоеточие (:) и ограничение, которое задает характер ограничений для параметра типа. where — контекстно-зависимое ключевое слово; дополнительные сведения см. в разделе Контекстные ключевые слова (расширения компонентов C++). Разделяйте несколько операторов where пробелом.

Ограничения применяются к аргументам типа, чтобы задать ограничение на типы, которые могут использоваться для универсальных типов и методов.

Ограничения класса и интерфейса определяют, что аргументы типов должны быть или наследованы от указанного класса, или реализовывать указанный интерфейс.

Применение ограничений к универсальному типу или методу позволяет коду в этом типе или методе использовать известные возможности ограниченных типов. Например, можно объявить универсальный класс такой, чтобы параметр типа реализовывал интерфейс IComparable<T>.

// generics_constraints_1.cpp
// compile with: /c /clr
using namespace System;
generic <typename T>
where T : IComparable<T>
ref class List {};

Это ограничение требует, чтобы аргумент типа, используемый для T, реализовывал IComparable<T> во время компиляции. Ограничение также позволяет использовать методы интерфейса, например, CompareTo. Для вызова методов интерфейса на экземпляре параметра типа не требуется преобразование типов.

Статические метода класса аргумента типа нельзя вызывать через параметр типа, они могут вызваны только через действительное имя типа.

Ограничение не может быть типом значения, включая встроенные типы, такие как int или double. Поскольку типы значений не могут иметь производные классы, только один класс сможет удовлетворить ограничение. В этом случае универсальный шаблон можно переписать с заменой параметра типа определенным типом значения.

Ограничения необходимых в некоторых случаях, поскольку компилятор не допускает использование методов или других функций неизвестного типа, если ограничения не будут определять, что неизвестный тип поддерживает методы или интерфейсы.

Несколько ограничений для одного параметра типа можно определить в списке, разделенном запятыми

// generics_constraints_2.cpp
// compile with: /c /clr
using namespace System;
using namespace System::Collections::Generic;
generic <typename T>
where T : List<T>, IComparable<T>
ref class List {};

При работе с несколькими параметрами типа используйте по одному оператору where для каждого параметра типа, например: Примеры.

// generics_constraints_3.cpp
// compile with: /c /clr
using namespace System;
using namespace System::Collections::Generic;

generic <typename K, typename V>
   where K: IComparable<K>
   where V: IComparable<K>
ref class Dictionary {};

В заключение, используйте ограничения в вашем коде в соответствии с этими правилами:.

  • Ограничения могут перечислены в любом порядке.

  • Ограничения могут также быть типами класса, например, абстрактные базовые классы. Однако ограничения не могут быть типами значений или sealed классами.

  • Ограничения не могут быть параметрами типа, но они могут включать параметры типа в открытый сконструированный тип. Примеры.

    // generics_constraints_4.cpp
    // compile with: /c /clr
    generic <typename T>
    ref class G1 {};
    
    generic <typename Type1, typename Type2>
    where Type1 : G1<Type2>   // OK, G1 takes one type parameter
    ref class G2{};
    

Пример

В следующем примере демонстрируется использование ограничений для вызова методов на экземпляре параметра типа.

// generics_constraints_5.cpp
// compile with: /clr
using namespace System;

interface class IAge {
   int Age();
};

ref class MyClass {
public:
   generic <class ItemType> where ItemType : IAge 
   bool isSenior(ItemType item) {
      // Because of the constraint,
      // the Age method can be called on ItemType.
      if (item->Age() >= 65) 
         return true;
      else
         return false;
   }
};

ref class Senior : IAge {
public:
   virtual int Age() {
      return 70;
   }
};

ref class Adult: IAge {
public:
   virtual int Age() {
      return 30;
   }
};

int main() {
   MyClass^ ageGuess = gcnew MyClass();
   Adult^ parent = gcnew Adult();
   Senior^ grandfather = gcnew Senior();

   if (ageGuess->isSenior<Adult^>(parent))
      Console::WriteLine("\"parent\" is a senior");
   else
      Console::WriteLine("\"parent\" is not a senior");

   if (ageGuess->isSenior<Senior^>(grandfather))
      Console::WriteLine("\"grandfather\" is a senior");
   else
      Console::WriteLine("\"grandfather\" is not a senior");
}
  

Если параметр универсального типа используется в качестве ограничения, оно называется открытым ограничением типа. Открытые ограничения типа полезны, когда функция-член со своим параметром типа должна ограничить этот параметр параметром типа универсального класса.

В следующем примере T является открытым ограничением типа в контексте метода Add.

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

// generics_constraints_6.cpp
// compile with: /clr /c
generic <class T>
ref struct List {
   generic <class U>
   where U : T
   void Add(List<U> items)  {}
};

generic <class A, class B, class C>
where A : C
ref struct SampleClass {};

См. также

Другие ресурсы

Универсальные типы и методы (расширения компонентов C++)