给定一个任意容器,推导出相关类型的容器类型
Giving an arbitrary container, deduce a container type of a related type
假设我有一个模板化的 class Wrapper
,有没有办法创建一个类型别名模板,自动从 [=13= 的容器中推导出 Wrapper <T>
的容器],因此:
alias(Wrapper, vector<int>)
会变成 vector<Wrapper<int>>
alias(Wrapper, map<int, string>)
会变成 map<Wrapper<int>, Wrapper<string>>
alias(Wrapper, array<int, 10>)
会变成 array<Wrapper<int>, 10>
到目前为止,我的最佳尝试是:
template<template<typename> typename U, template<typename...> typename Container, typename ...T>
using alias = std::remove_cvref_t<decltype(std::declval<Container<U<T>...>>())>;
但是有两个问题:
必须使用如下语法调用:此版本需要这样调用(这并不理想):alias(vector, Type)
和 alias(map, Key, Value)
。如果可能的话,我很乐意使用 alias(vector<Type>)
和 alias(map<Key, Value>)
。
与std::array
不兼容,因为array
的第二个模板参数size_t
不是类型。我想我可以创建第二个类型别名并根据容器类型调用相应的别名,但我宁愿不必这样做。
目前没有办法将非类型模板参数与类型模板参数或模板模板参数混合使用。
那么对于您的 alias
仅限于类型模板参数,您可以这样做:
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;
用法是
alias_t<Wrapper, vector<int>>
而不是 alias(Wrapper, vector<int>)
.
但如评论中所述,通用方式将包装所有参数,包括默认参数(例如Allocator
)。
选择 Marek R 展示的专业可能更合适。
不确定这是否正是您所需要的,但是 class 模板的专业化可以很好地处理这个问题:
#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
它通过了您指定的测试。
假设我有一个模板化的 class Wrapper
,有没有办法创建一个类型别名模板,自动从 [=13= 的容器中推导出 Wrapper <T>
的容器],因此:
alias(Wrapper, vector<int>)
会变成vector<Wrapper<int>>
alias(Wrapper, map<int, string>)
会变成map<Wrapper<int>, Wrapper<string>>
alias(Wrapper, array<int, 10>)
会变成array<Wrapper<int>, 10>
到目前为止,我的最佳尝试是:
template<template<typename> typename U, template<typename...> typename Container, typename ...T>
using alias = std::remove_cvref_t<decltype(std::declval<Container<U<T>...>>())>;
但是有两个问题:
必须使用如下语法调用:此版本需要这样调用(这并不理想):alias(vector, Type)
和alias(map, Key, Value)
。如果可能的话,我很乐意使用alias(vector<Type>)
和alias(map<Key, Value>)
。与
std::array
不兼容,因为array
的第二个模板参数size_t
不是类型。我想我可以创建第二个类型别名并根据容器类型调用相应的别名,但我宁愿不必这样做。
目前没有办法将非类型模板参数与类型模板参数或模板模板参数混合使用。
那么对于您的 alias
仅限于类型模板参数,您可以这样做:
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;
用法是
alias_t<Wrapper, vector<int>>
而不是 alias(Wrapper, vector<int>)
.
但如评论中所述,通用方式将包装所有参数,包括默认参数(例如Allocator
)。
选择 Marek R 展示的专业可能更合适。
不确定这是否正是您所需要的,但是 class 模板的专业化可以很好地处理这个问题:
#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
它通过了您指定的测试。