条件宏或扩展模板

Conditional Macros or expanding templates

本文关键字:扩展 条件      更新时间:2023-10-16

我有一个这样的模板化结构:

class Context {
    template<typename T>
    T construct();
};
template<typename T, typename ...Args>
struct aggregate {
    T construct(Context& ctx) {
        return { std::move(ctx.construct<Args>())... };
    }
};

这个问题很容易看出:当用户请求像这样使用它时:

typedef struct {
    float xyz[3];
} Vector3;
using ConstructVector = aggregate<Vector3, float[3]>;

这里会生成一个错误,因为这会调用模板化函数Context.construct T = float[3]导致函数返回数组。因此,我想要的是某种方式来扩展{ std::move(ctx.construct<Args>())... }{{ std::move(ctx.construct<float>()), std::move(ctx.construct<float>()), std::move(ctx.construct<float>()) }}或更通用,任何类型 T 的数组(constexpr 大小为 N)都应该扩展到一个重复std::move(ctx.construct<T>()) N次的构造,并且应该包装在一对额外的{}中。

这是一种错误的方法吗?有没有另一种方法可以初始化聚合语句中的值数组?


我从 g++ (4.9.1) 收到以下错误:

C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/utilitysupplier.hpp: In instantiation of 'typename io::Supplier<T>::item_t io::utility::aggregate_supplier<T, args>::supply(io::Context&) const [with T = Vector3; args = float [3]; typename io::Supplier<T>::item_t = Vector3]':
../test/main.cpp:185:1:   required from here
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/utilitysupplier.hpp:42:37: error: no matching function for call to 'io::Context::construct()'
   return { ctx.construct<args>()... };
                                     ^
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/utilitysupplier.hpp:42:37: note: candidate is:
In file included from C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Context.hpp:141:0,
                 from C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Reader.hpp:13,
                 from C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Environment.hpp:12,
                 from ../test/main.cpp:14:
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Context.tpp:37:28: note: template<class T> typename io::supply_t<T>::type io::Context::construct()
 typename supply_t<T>::type Context::construct() {
                            ^
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Context.tpp:37:28: note:   template argument deduction/substitution failed:
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Context.tpp: In substitution of 'template<class T> typename io::supply_t<T>::type io::Context::construct() [with T = float [3]]':
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/utilitysupplier.hpp:42:37:   required from 'typename io::Supplier<T>::item_t io::utility::aggregate_supplier<T, args>::supply(io::Context&) const [with T = Vector3; args = float [3]; typename io::Supplier<T>::item_t = Vector3]'
../test/main.cpp:185:1:   required from here
C:UsersCarbonDocumentsCreativeWorkspaceEpicRPGSmartIO/smartio/Context.tpp:37:28: error: function returning an array

生成嵌套的大括号初始化列表是不可能的,但生成一个扁平化列表是可能的,并且适合聚合。

下面显示的方法在 std::make_index_sequence 的帮助下使用 C++14,但您也可以在 C++11 中实现这样的事情:

template<class... Ts>
struct list;
template<class A, class B>
struct merge;
template<class... As, class... Bs>
struct merge<list<As...>, list<Bs...>>
{
    using type = list<As..., Bs...>;
};
template<std::size_t N, class T>
using just = T;
template<class T, class Index>
struct repeat_impl;
template<class T, std::size_t... Ns>
struct repeat_impl<T, std::index_sequence<Ns...>>
{
    using type = list<just<Ns, T>...>;
};
template<class T, int N>
using repeat = typename repeat_impl<T, std::make_index_sequence<N>>::type;
template<class T>
struct to_list
{
    using type = list<T>;
};
template<class T, int N>
struct to_list<T[N]>
{
    using type = repeat<T, N>;
};
template<class... Ts>
struct flatten;
template<>
struct flatten<>
{
    using type = list<>;
};
template<class T, class... Ts>
struct flatten<T, Ts...>
{
    using type = typename merge<typename to_list<T>::type, typename flatten<Ts...>::type>::type;
};

flatten<float[3], int[2]>::typelist<float, float, float, int, int, int>回报你.

现在我们可以实现如下aggregate

struct Context
{
    template<typename T>
    T construct();
};
template<class T, class List>
struct aggregate_impl;
template<class T, class... Args>
struct aggregate_impl<T, list<Args...>>
{
    static T construct(Context& ctx)
    {
        return {ctx.construct<Args>()...};
    }
};
template<class T, class... Args>
using aggregate = aggregate_impl<T, typename flatten<Args...>::type>;

现在您可以执行以下操作:

using ConstructVector = aggregate<Vector3, float[3]>;
Context ctx;
ConstructVector::construct(ctx);

现场演示