c++ - 条件宏或扩展模板

标签 c++ arrays c++11 recursion

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

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.constructT = 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:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/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:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/utilitysupplier.hpp:42:37: error: no matching function for call to 'io::Context::construct()'
   return { ctx.construct<args>()... };
                                     ^
C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/utilitysupplier.hpp:42:37: note: candidate is:
In file included from C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/Context.hpp:141:0,
                 from C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/Reader.hpp:13,
                 from C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/Environment.hpp:12,
                 from ../test/main.cpp:14:
C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/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:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/Context.tpp:37:28: note:   template argument deduction/substitution failed:
C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/Context.tpp: In substitution of 'template<class T> typename io::supply_t<T>::type io::Context::construct() [with T = float [3]]':
C:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/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:\Users\Carbon\Documents\CreativeWorkspace\EpicRPG\SmartIO/smartio/Context.tpp:37:28: error: function returning an array

最佳答案

生成一个嵌套的 braced-init 列表是不可能的,但是生成一个扁平的列表是可能的并且适合聚合。

不过,在 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]>::type会还你list<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);

LIVE DEMO

关于c++ - 条件宏或扩展模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27400383/

相关文章:

c++ - OpenCV 中的转换概念

c++ - 我怎样才能让我的非常大的程序链接起来?

c++ - int8_t 和 uint8_t 是 char 类型吗?

C++ 将数组分配给彼此; type int* = type int 有效但 int = int*?

c++ - Variadic Template C++ 中的静态 const 值数组

c++ - 对集合的键类型使用比较函数会导致运行时错误

c++ - “AES_ctr128_encrypt”未在此范围内声明

c++ - 为什么 std::unordered_map::count 上没有 `noexcept` 说明符?

javascript - 我们可以将两个函数作为参数传递给另一个函数吗?

arrays - 在 Swift 中确定多维数组的大小