Частичная специализация шаблона над созданным и не реализованным шаблоном - PullRequest
3 голосов
/ 18 апреля 2019

У меня есть две следующие структуры:

template<typename T>
struct one { /* ... */ };

template<template<typename...> typename T>
struct two { /* ... */ };

Когда у меня есть примеры созданных / неустановленных шаблонов, подобных этому:

template<typename T>
struct sample_templated { /* ... */ };

using instantiated = sample_templated<double>;

тогда я могу сделать

one<instantiated>{};
two<sample_templated>{};

просто отлично. Я хотел бы объединить определения one и two так, чтобы они имели одно и то же имя, поскольку это позволило бы рекурсию.

Я попытался использовать определение по умолчанию, например

template<typename...>
struct types_match_impl;

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

Какое здесь решение?

1 Ответ

3 голосов
/ 18 апреля 2019

То, на что вы надеетесь, невозможно. И вот почему:

one<instantiated>{};
two<sample_templated>{};

one «использует» больше, чем two: это относится к instantiated, которому sample_templated соответствует double. two, с другой стороны, только «использует» sample_templated.

Когда вы думаете о шаблонах как о функциях над типами, это становится еще понятнее: two - это функция, которая принимает функцию (на уровне типа) для создания некоторого типа. one - это функция, которая принимает тип для создания некоторого типа:

one :: T -> one<T>
two :: (T -> U) -> two<(T -> U)>

Иными словами, параметр one имеет другой "вид" ("тип типа"), чем параметр two.

Что вы можете сделать:

  • Можно указать специализацию one, которая принимает параметр шаблона шаблона («функция уровня типа») и параметр шаблона для этого:

    template<template<typename...> typename TT, typename T>
    struct one<TT<T>>  { /* ... */ }; // this basically "calls" TT
    
  • Вы можете превратить two во что-то, что может принимать и то и другое, хотя и с "фиктивным" параметром шаблона шаблона:

    template<template<typename...> typename TT, typename... Ts>
    struct two { /* */ };
    
    template<typename...>
    struct Void;
    
    template<typename T>
    struct two<Void<>, T> { /* Use T like in one */ };
    // or derive from one<T>
    

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...