You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现支持任意类型容器的compile-time type list映射?

Generalizing MapVariant to Work with Any Type-List Container (like std::tuple)

Absolutely, this generalization is totally feasible! The key issue with your previous attempts is that you're trying to work directly with the instantiated container type (like TestVariant, which is std::variant<int, char, std::array<float, 0>>) but haven't set up a way to extract the underlying container template and its type parameters automatically. Let's fix this step by step.

Correct Implementation

First, we need a helper trait that can decompose any instantiated container into its template and the list of type parameters. Here's the robust solution:

#include <type_traits>

namespace impl_ {
    // Primary template: fallback for non-template-instantiation types
    template <typename Container, template <typename> typename Transform>
    struct MapContainer;

    // Specialization for variadic type-only containers (variant, tuple, etc.)
    template <template <typename...> typename ContainerTemplate, typename... Ts, template <typename> typename Transform>
    struct MapContainer<ContainerTemplate<Ts...>, Transform> {
        // Apply transform to each type and repack into the original container template
        using Result = ContainerTemplate<Transform<Ts>...>;
    };

    // Optional: Specialization for std::array (handles non-type size parameter)
    template <typename T, std::size_t N, template <typename> typename Transform>
    struct MapContainer<std::array<T, N>, Transform> {
        using Result = std::array<Transform<T>, N>;
    };
}

// User-facing alias for simplicity
template <typename Container, template <typename> typename Transform>
using MapContainer = typename impl_::MapContainer<Container, Transform>::Result;

How This Works

  • The primary MapContainer template acts as a fallback for types that aren't template instantiations (we don't need to handle these for your use case).
  • The core specialization matches any type that's an instance of a variadic type-only template (like std::variant or std::tuple). It extracts:
    • ContainerTemplate: The original container template (e.g., std::variant)
    • Ts...: The type parameters inside the container
    • Transform: Your type-level transformation function
  • We then create the result by applying Transform to each Ts and repacking them into the original container template.
  • The optional std::array specialization handles containers with non-type parameters (the size N in this case).

Test Cases

Let's verify this works with your original variant, a tuple, and an array:

#include <variant>
#include <tuple>
#include <array>
#include <string>

// Your original transformation
template <typename Arg>
using TypeTransform = std::array<Arg, 0>;

// Test variant transformation
using TestVariant = std::variant<int, char, std::array<float, 0>>;
static_assert(
    std::is_same_v<MapContainer<TestVariant, TypeTransform>,
        std::variant<std::array<int, 0>, std::array<char, 0>, std::array<std::array<float, 0>, 0>>
    >,
    "Variant mapping failed!"
);

// Test tuple transformation
using TestTuple = std::tuple<int, double, std::string>;
static_assert(
    std::is_same_v<MapContainer<TestTuple, TypeTransform>,
        std::tuple<std::array<int, 0>, std::array<double, 0>, std::array<std::string, 0>>
    >,
    "Tuple mapping failed!"
);

// Test array transformation
using TestArray = std::array<int, 5>;
static_assert(
    std::is_same_v<MapContainer<TestArray, TypeTransform>,
        std::array<std::array<int, 0>, 5>
    >,
    "Array mapping failed!"
);

Why Your Previous Attempts Failed

  1. The "simple" version:

    template <template <typename...> class C, template <typename> typename F, typename... Ts>
    using MapVariant = C<F<Ts>...>;
    

    This requires you to pass the container template (e.g., std::variant) and type list (e.g., int, char) separately, but you want to pass the already-instantiated TestVariant directly. It doesn't decompose the existing container type automatically.

  2. The verbose version:
    Your second attempt had mismatched template parameters and couldn't correctly infer the container template from the instantiated type. The compiler error about "template argument for template template parameter must be a class template" came from trying to pass Variant<Ts...> (an instantiated type) where a template template parameter (like std::variant) was expected.

内容的提问来源于stack exchange,提问作者Pavel Kirienko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:32:29