2015-06-30 2 views
3

Я пытаюсь преобразовать следующий код C# в D, однако я не могу понять, как заставить ограничения шаблона работать.DLang - Ограничения шаблона - тип должен реализовывать интерфейс

C# Реализация

public interface IComponent 
{ 

} 

public class Container 
{ 
    public T CreateComponent<T>() where T: IComponent, new() 
    { 
     // Trivial initialisation for example 
     var t = new T(); 
     return t; 
    } 
} 

D

деле ввода
public interface Component 
{ 

} 

public class Container 
{ 
    public T createComponent(T)() 
    { 
     // Trivial initialisation for example 
     auto t = new T(); 
     return t; 
    } 
} 

Как я могу заново создать "где T: IComponent" ограничение?

Я пробовал различные сочетания выражений, typeof и т. Д., Но не могу найти ничего, что сработает.

ответ

4

Ну, если все, что вы пытаетесь сделать, это требует, чтобы T реализовать интерфейс IComponent, то is(T : IComponent) будет проверять, что T неявно конвертируется в IComponent (это тот случай, когда IComponent является базовым классом T или интерфейсом, который он реализует). Таким образом, вы в конечном итоге с чем-то вроде

public class Container 
{ 
    public T createComponent(T)() 
     if(is(T : IComponent)) 
    { 
     // Trivial initialisation for example 
     auto t = new T(); 
     return t; 
    } 
} 

Теперь, технически, другие вещи могут соответствовать, если alias this используется для определения неявное преобразование, которое не является, вероятно, будет общим, но если вы быть более параноидальный об этом, вы можете сделать ограничение также проверить, что T является классом - is(T == class).

public class Container 
{ 
    public T createComponent(T)() 
     if(is(T == class) && is(T : IComponent)) 
    { 
     // Trivial initialisation for example 
     auto t = new T(); 
     return t; 
    } 
} 

Затем T должен быть классом, и он должен неявно преобразовать в IComponent. Тем не менее, это является еще технически возможно T быть класс, который не реализует IComponent но определить alias this, который преобразует к IComponent (это уже просто не возможно T быть структура, которая делает это). Таким образом, это не идеально, но я не знаю, как обеспечить неявное преобразование через наследование, а не alias this. Поэтому, к сожалению, я не знаю, как абсолютно гарантировать, что T - это класс, который реализует IComponent. Самое главное, что я знаю, как сделать, это убедиться, что он неявно преобразуется в «IComponent», который почти всегда означает, что он его реализует.

Однако реальность заключается в том, что в подавляющем большинстве случаев просто проверка is(T : IComponent) - это много, и в зависимости от того, как написан ваш код, он может работать даже с типом, который неявно преобразуется в IComponent, но isn ' t фактически IComponent. Таким образом, факт, что alias this выбрасывает гаечный ключ в работах, на самом деле не может быть проблемой. Однако, вообще говоря, alias this - это проклятие общего кода и почему большинство общих кодов не должны проверять неявные преобразования.Слишком легко для типа неявно конвертировать через alias this, но фактически не быть преобразованным в функцию, и в этом случае он либо не будет компилироваться, либо может иметь странное поведение, если он поддерживает те же операции, что и тип цели, но эти операции не имеют таких же результатов, как если бы исходный тип был фактически преобразован в целевой тип. Итак, если вы на самом деле хотите неявных преобразований в шаблоном коде, вы должны принудительно ввести неявное преобразование, назначив аргумент целевому типу. Но поскольку вы хотите проверить интерфейс, а не неявные преобразования в целом, то, что вы, вероятно, хотите, - это тест, который проверяет это, не допуская неявных преобразований через alias this. К сожалению, единственный способ, который, как я знаю, проверять во время компиляции, является ли один тип производным от другого или реализует конкретный интерфейс, - проверить, неявно ли он преобразуется в этот базовый класс или интерфейс.

Но, может быть, есть какое-то забавное вуду с чертами, которые на самом деле способны это сделать. Если есть, мы должны, вероятно, добавить что-то к std.traits, который сделает это за вас, а если нет, возможно, нам стоит найти способ добавить его, поскольку alias this может определенно быть раздражающим, если вы этого не хотите. Но, к счастью, это не проблема, возникающая в большинстве кодов, и если вы не пишете публичный API, вам нужно только беспокоиться об этом, если вы объявляете типы с alias this. Если нет, тогда это действительно не имеет значения.

3

Вам не нужно даже шаблон ограничение, только специализация шаблона:

T createComponent(T : IComponent)() { /* some code */ } 
+0

На самом деле, это _does_ матч структуры и классы, которые имеют 'псевдоним this', который преобразует к' IComponent' (я просто попытался убедиться). Таким образом, это действительно не отличается от использования ограничения шаблона в этом случае. Это немного короче. Лично я склонен забывать, что такие типовые специализации существуют в D, потому что ограничения шаблонов намного более мощные, и вам часто нужна эта дополнительная сила. Таким образом, специализированные шаблоны часто не работают, и они являются избыточной функцией (но сначала возникли специализированные шаблоны, поэтому мы и то, и другое). –

+0

Когда я увидел этот вопрос, этот ответ впервые пришел мне на ум. Мне нравятся ограничения шаблонов, но я смиренно считаю, что они делают код менее читаемым, а затем простые специализированные шаблоны. – DejanLekic

+0

@JonathanMDavis Я попробовал 'createComponent! SomeStructWithAliasThis', и он не компилировался для меня. Я скоро попробую пример. –

Смежные вопросы