条件宏或扩展模板
Conditional Macros or expanding templates
我有一个这样的模板化结构:
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]>::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);
现场演示
相关文章:
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 在没有太多条件句的情况下,我如何避免被零除
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 基于多个条件处理地图中的所有元素
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 条件constexpr函数
- 无论条件是否为true,if总是在c++中执行
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 基于模板值的条件变量
- 如何将这个C++哈希表转换为动态扩展和收缩,而不是使用硬设置的最大值
- 扩展光电二极管探测器以支持多个传感器
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 如何在C++中定义扩展到条件语句的宏?
- C ;使用lambdas在类中有条件地扩展功能(MWE的SEG故障)
- AVX2 根据条件将连续元素扩展到稀疏向量?(如AVX512 VP扩展)
- 可扩展的 SFINAE 条件覆盖
- 在相同条件下扩展多个"if"可提高性能
- 可扩展条件语句的机制
- 条件宏或扩展模板
- 生存期扩展和条件运算符