Update
我注意到附加要求std::tuple
参数可以处于任何位置。以下允许传递类型或用 包裹的类型std::tuple
以任意顺序作为模板参数。它只需要比原来的方法多一个专业化。
有四个专业需要处理:
- 唯一的模板参数是
std::tuple
- 第一个模板参数不是
std::tuple
- 第一个模板参数是
std::tuple
但第二个不是
- 第一个和第二个模板参数是
std::tuple
基本情况是一个单一的std::tuple
模板参数。这很容易翻译成包装的std::variant
。所有其他情况都相互递归或递归到基本情况。
#include <type_traits>
#include <tuple>
#include <variant>
template<template<class> class T, class... Ts>
struct variant_wrapper_impl;
// The base case is that all types come packaged in a single tuple.
template<template<class> class T, class... Ts>
struct variant_wrapper_impl<T, std::tuple<Ts...>> {
using type = std::variant<T<Ts>...>;
};
// The first type is not a tuple.
template<template<class> class T, class U, class... Us>
struct variant_wrapper_impl<T, U, Us...> {
using type = typename variant_wrapper_impl<T, std::tuple<U>, Us...>::type;
};
// The first type is a tuple and the second type is not a tuple.
template<template<class> class T, class... Ts, class U, class... Us>
struct variant_wrapper_impl<T, std::tuple<Ts...>, U, Us...> {
using type = typename variant_wrapper_impl<T, std::tuple<Ts..., U>, Us...>::type;
};
// The first type is a tuple and the second type is a tuple.
template<template<class> class T, class... Ts, class... Us, class... Ws>
struct variant_wrapper_impl<T, std::tuple<Ts...>, std::tuple<Us...>, Ws...> {
using type = typename variant_wrapper_impl<T, std::tuple<Ts..., Us...>, Ws...>::type;
};
template<template<class> class T, class... Ts>
using variant_wrapper_t = typename variant_wrapper_impl<T, Ts...>::type;
template<class T>
class Wrapper {
};
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, int, float>,
std::variant<Wrapper<int>, Wrapper<float>>>);
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, std::tuple<int, float>>,
std::variant<Wrapper<int>, Wrapper<float>>>);
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, std::tuple<int, float>, double>,
std::variant<Wrapper<int>, Wrapper<float>, Wrapper<double>>>);
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, char, std::tuple<int, float>, double>,
std::variant<Wrapper<char>, Wrapper<int>, Wrapper<float>, Wrapper<double>>>);
int main(int argc, const char *argv[]) {
return 0;
}
结束更新
我认为以下内容可以满足您的要求。关键思想是部分专业化variant_wrapper_imp
处理元组子类型的展开。
#include <type_traits>
#include <tuple>
#include <variant>
template<template<class> class T, class... Ts>
struct variant_wrapper_impl;
// The simple case: W, int, float -> variant<W<int>, W<float>>
template<template<class> class T, class... Ts>
struct variant_wrapper_impl {
using type = std::variant<T<Ts>...>;
};
// The tuple case: W, tuple<int, float> -> variant<W<int>, W<float>>
//
// We use the pattern matching of partial specialization to extract
// the tuple sub-types into Ts...
template<template<class> class T, class... Ts>
struct variant_wrapper_impl<T, std::tuple<Ts...>> {
using type = std::variant<T<Ts>...>;
};
// The tuple+ case: W, tuple<int, float>, double -> variant<W<int>, W<float>, W<double>>
//
// We again use the pattern matching of partial specialization to
// extract the tuple sub-types into Ts.. and then recurse to the simple case.
template<template<class> class T, class... Ts, class... Us>
struct variant_wrapper_impl<T, std::tuple<Ts...>, Us...> {
using type = typename variant_wrapper_impl<T, Ts..., Us...>::type;
};
template<template<class> class T, class... Ts>
using variant_wrapper_t = typename variant_wrapper_impl<T, Ts...>::type;
template<class T>
class Wrapper {
};
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, int, float>,
std::variant<Wrapper<int>, Wrapper<float>>>);
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, std::tuple<int, float>>,
std::variant<Wrapper<int>, Wrapper<float>>>);
static_assert(std::is_same_v<variant_wrapper_t<Wrapper, std::tuple<int, float>, double>,
std::variant<Wrapper<int>, Wrapper<float>, Wrapper<double>>>);
int main(int argc, const char *argv[]) {
return 0;
}