在元编程中强制执行不变量
Enforcing invariants in metaprogramming
我希望能够检查元程序中使用的类的不变量。我的第一个天真的方法是
template <int N>
struct digit
{
static_assert((N >= 0) && (N < 10), "bad invariant");
};
using boom = digit<99>;
然而,这编译起来没有任何问题。只有当构造了非法类时,才会触发静态断言。
当添加额外的模板参数时是可能的:
#include <type_traits>
template <int N,
typename = typename std::enable_if<(N >= 0) && (N < 10)>::type>
struct digit;
using crash = digit<-7>;
当我想将这种技术应用于一个用作类型列表的类时:
#include <type_traits>
template <typename ...> struct are_integral;
template <typename T, typename ...Ts>
struct are_integral<T, Ts...>
{
static const bool value = std::is_integral<T>::value &&
are_integral<Ts...>::value;
};
template <>
struct are_integral<> : std::true_type { };
template <typename ...Ts,
typename = typename std::enable_if<are_integral<Ts...>::value>::type>
struct list;
using ok = list<int, long, char>;
using bad = list<double>;
它根本不起作用,因为gcc抱怨
错误:参数包"Ts"必须位于模板的末尾参数列表结构列表;
即使它可以工作,该类也是无用的,因为模板参数包没有反映类型列表。
所以我尝试使用一个"非法"基类:
template <typename> struct check;
template <typename ...Ts>
struct list : check<typename std::enable_if<are_integral<Ts...>::value>::type>
{ };
using ok = list<int, long, char>;
using bad = list<double>;
这编译起来没有问题。
有没有办法在c++11中完成这样的事情,或者我必须等待概念?
您的问题是因为模板在别名时没有实例化,所以static_assert不会触发。
如果这是可以接受的,您可以添加一些间接方法,并使用构建器元函数来创建编译时列表。此元函数将执行检查。
template <typename ...Ts>
struct make_list
{
static_assert(are_integral<Ts...>::value, "all types must be integral");
typedef list<Ts...> type;
};
using ok = make_list<int, long, char>::type;
using bad = make_list<double>::type;
另一种解决方案是使用伪类型将参数包封装为一类类型。
// dummy wrapper
template <typename ...>
struct pack;
template <typename ...> struct are_integral;
// specialization for wrapped packs
template <typename ...Ts>
struct are_integral<pack<Ts...>> : are_integral<Ts...>
{
};
template <typename T, typename ...Ts>
struct are_integral<T, Ts...>
{
static const bool value = std::is_integral<T>::value &&
are_integral<Ts...>::value;
};
template <>
struct are_integral<> : std::true_type { };
// helper type which performs the check
template <typename Pack,
typename = typename std::enable_if<are_integral<Pack>::value>::type>
struct list_helper;
// actual type (alias) you will expose
template <typename ...Ts>
using list = list_helper<pack<Ts...>>;
using ok = list<int, long, char>;
using bad = list<double>; // compiler error
在处理参数包时,使用包装器通常很方便,因为它使它们更易于操作:包装器是一种与其他类型类似的类型,可以存储、出现在参数列表中的任何位置、传递给一元函数等。
相关文章:
- 使用不变量来确定二分搜索中的边界条件
- C++变量等于不变量
- 有没有一种通用的方法来实现不变量
- 如何执行不区分大小写的字符串比较?
- 有没有办法强制C++编译器将变量存储在寄存器中?
- 如何在构造函数中传递 const 引用时强制编译器不接受右值
- 具有管理员权限的外壳执行不会结束
- 未能优化看似明显的循环不变量(但volatile限定符发挥了神奇的作用)
- 如何对模板类型强制执行常量
- C++:我可以在模板参数包中强制执行至少1个agment吗
- 删除单个构造会导致执行不正确
- 编译器未强制执行返回协定
- 如何在 Linux 上强制执行矢量下标超出范围的调试断言
- 如何使用C++模板强制执行正式协议?
- 并行执行不更新我的变量
- 内存访问:为什么它不会崩溃以及如何强制执行它?
- Eclipse的代码标准(而不是样式)强制执行器
- 在元编程中强制执行不变量
- 为什么在编译时不强制执行 noexcept
- 为什么不在C++中强制执行 2 的补码?