我有一个类模板,本质上想为将公开给 API 用户的变体类型创建一个模板别名:
template <bool InsertsAllowed, DeletesAllowed>
class Executor {
...
public:
// Ideally, would be
// std::variant<ReadRequest, {InsertRequest only if InsertsAllowed}, {DeleteRequest only if DeletesAllowed}>
// e.g. InsertsAllowed = true, DeletesAllowed = False ==> std::variant<ReadRequest, InsertRequest>
// InsertsAllowed = true, DeletesAllowed = True ==> std::variant<ReadRequest, InsertRequest, DeleteRequest>
using RequestType = ...
makeRequest(const RequestType &r);
...
}
到目前为止,我能想到的最好的解决方案是
template <bool InsertsAllowed, DeletesAllowed>
class Executor {
...
public:
struct BAD_TYPE = {};
using RequestType = std::variant<
ReadRequest,
std::conditional<InsertsAllowed, InsertRequest, BAD_TYPE>,
std::conditional<DeleletesAllowed, DeleteRequest, BAD_TYPE>>;
makeRequest(const RequestType &r);
...
}
但这并没有完全达到我想要实现的目标,而且也不是最干净的解决方案。
我需要能够引用
RequestType
,所以不幸的是我无法用BAD_TYPE
替换void
。另外,我想避免堆叠一堆条件来实现我的目标,以防我需要添加更多模板参数来达到类似的效果。
首先,您需要创建一个元函数,以有条件地将另一种类型附加到
std::variant
的模板列表中。让我们命名它condit_append
:
#include <type_traits>
#include <variant>
template<bool cond, typename A, typename B>
struct condit_append;
template<bool cond, typename U, typename ...T>
struct condit_append<cond, std::variant<T...>, U>
{
using type = std::conditional_t<cond,
std::variant<T..., U>,
std::variant<T...>
>;
};
接下来,让我们为其创建一个方便的别名,类似于标准特征的做法:
template<bool cond, typename ...T>
using condit_append_t = typename condit_append<cond, T...>::type;
最后,将其用于您的课程:
class ReadRequest;
class InsertRequest;
class DeleteRequest;
template <bool InsertsAllowed, bool DeletesAllowed>
class Executor {
using Type1 = std::variant<ReadRequest>;
using Type2 = condit_append_t<InsertsAllowed,Type1, InsertRequest>;
using RequestType = condit_append_t<DeletesAllowed,Type2, DeleteRequest>;
//...
};