Мне было интересно, можно ли написать функцию шаблона, которая может принимать любой другой произвольный шаблон в качестве параметра и правильно соответствовать имени шаблона (т.е. не только результирующий класс). Я знаю, что это работает:
template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);
Которое будет соответствовать, например, для f(std::vector<int>())
или f(std::list<int>())
, но не будет работать для f(std::array<int, 3>())
, так как вторым параметром является size_t
и нет типа.
Теперь я думаю, что можно было сделать что-то сумасшедшее, как:
template<template<typename ...> class TemplateT, size... Sizes, typename... TemplateP>
void f(const TemplateT<Sizes..., TemplateP...>& param);
Надеясь, что компилятор будет правильно выводить эллипсис TemplateP
или Sizes
, чтобы быть пустым. Но не только это уродливо, но и будет работать только для шаблонов, которые принимают либо типы, либо параметры size_t
. Он по-прежнему не будет соответствовать произвольным шаблонам, например, с параметрами bool
.
То же самое касается подхода с перегрузкой:
template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);
template<template<typename ...> class TemplateT, size... Sizes>
void f(const TemplateT<Sizes...>& param);
Кроме того, такой подход не будет работать, если мы хотим смешивать size_t
и typenames
. Итак, что требовалось бы, чтобы соответствовать чему-либо, было бы что-то вроде этого, где нет никаких ограничений на то, что разрешено в многоточии:
template<template<...> class TemplateT, ... Anything>
void f(const TemplateT<Anything...>& param);
Этот синтаксис не работает, но может быть, есть другой синтаксис, чтобы определить что-то вроде этого?
Это в основном меня интересует, что возможно на языке, считая, что на самом деле может быть полезно для него, если у вас разные шаблоны, где первый параметр всегда исправлен, и вы хотели бы изменить его на основе типа возврата и держите все остальное. Что-то вроде этого:
template<
template<typename ValueT, ...> class TemplateT,
... Anything,
typename ValueT,
typename ResultT = decltype(some_operation_on_value_t(std::declval<ValueT>())>
TemplateT<ResultT, Anything...> f(const TemplateT<ValueT, Anything...>& in);
Итак, любой способ сделать эту работу полностью универсальным способом с использованием сопоставления шаблонов?
Это не просто мысленный эксперимент, так как прецедент для этого, где я застрял, заключался в создании чистых функциональных примитивов, которые работают на контейнерах, и неявно создадут неизменяемые контейнеры результатов. Если контейнер результатов имеет другой тип данных, нам нужно знать тип, в котором работает контейнер, поэтому единственным требованием для любого контейнера было бы то, что первым параметром шаблона должен быть тип ввода, чтобы его можно было заменить другим тип вывода в результате, но код должен быть не обратим внимания на любой аргумент шаблона, следующий за ним, и не должен заботиться о том, является ли он типом или значением.