Say I have a templated class Wrapper
, is there a way to create a type alias template that automatically deduce a container of Wrapper <T>
from a container of T
, so that:
alias(Wrapper, vector<int>)
would becomevector<Wrapper<int>>
alias(Wrapper, map<int, string>)
would becomemap<Wrapper<int>, Wrapper<string>>
alias(Wrapper, array<int, 10>)
would becomearray<Wrapper<int>, 10>
So far the best attempt I've got is:
template<template<typename> typename U, template<typename...> typename Container, typename ...T>
using alias = std::remove_cvref_t<decltype(std::declval<Container<U<T>...>>())>;
However there are two problems:
It must be called with syntax like:This version need to be called like(which is not ideal):alias(vector, Type)
andalias(map, Key, Value)
. I would love to usealias(vector<Type>)
andalias(map<Key, Value>)
if possible.It is not compatible with
std::array
since the second template parameter ofarray
issize_t
not a type. I guess I could create a second type alias and call the corresponding one based on the container type, but I would prefer not have to do that.
CodePudding user response:
Not sure if this is exactly what you need, but specialization of class template can handle this nicely:
#include <type_traits>
#include <vector>
#include <array>
#include <map>
#include <string>
template<template<typename> typename Wrapper, typename Container>
struct repack;
template<template<typename> typename Wrapper, typename ValueT>
struct repack<Wrapper, std::vector<ValueT>>
{
using type = std::vector<Wrapper<ValueT>>;
};
template<template<typename> typename Wrapper, typename ValueT, std::size_t N>
struct repack<Wrapper, std::array<ValueT, N>>
{
using type = std::array<Wrapper<ValueT>, N>;
};
template<template<typename> typename Wrapper, typename Key, typename Value>
struct repack<Wrapper, std::map<Key, Value>>
{
using type = std::map<Wrapper<Key>, Wrapper<Value>>;
};
template<template<typename> typename Wrapper, typename Container>
using repack_t = typename repack<Wrapper, Container>::type;
https://godbolt.org/z/naz9v48vb
It passes tests specified by you.
CodePudding user response:
There are no ways currently to be generic and mix non-type-template-parameters with type-template-parameter or template-template-parameter.
Then for your alias
restricted to type-template-parameter, you might do something like:
template <template <typename> class Inner, typename Container>
struct alias;
template <template <typename> class Inner,
template <typename...> class C,
typename... Ts>
struct alias<Inner, C<Ts...>>
{
using type = C<Inner<Ts>...>;
};
template <template <typename> class Inner, typename Container>
using alias_t = typename alias<Inner, Container>::type;
usage would be
alias_t<Wrapper, vector<int>>
and not alias(Wrapper, vector<int>)
.
But as mentioned in comment, the generic way will wrap all parameters, including the default ones (such as Allocator
).
Selecting the specializations as Marek R showed might be more appropriate.