我有一个像这样的模板化结构:
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:\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);
关于c++ - 条件宏或扩展模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27400383/