使用模板元编程实现静态版本的std :: all_of?

时间:2014-12-01 03:51:40

标签: c++ c++11 template-meta-programming fold

前言即可。我试图对C ++模板元编程有一些更深入的了解,似乎我被卡住了...我正在编写一个库,我们将用它来进行二进制数据[de]序列化。正在解压缩的数据的预期结构在某种程度上是已知的,并且使用这些知识(1)验证数据(2)跳过不相关的部分以及(3)将数据直接解压缩到编译时已知的结构中似乎是合理的。 - 既可以避免不必要的复制,也可以使客户端代码看起来更清晰。

所以,例如,我想实现一个解包数组的函数(数组可以包含异构数据,比如JSON)。为简单起见,我们假设数组具有固定大小,并且没有嵌套。


实际问题我想编写一个函数,它将包含一个包含序列化数据的输入缓冲区(或一个流 - 它在我们的上下文中并不重要)和一个{{1}包含输出的左值(参数包是一个更糟糕的选择,因为我最终必须处理嵌套)。因此,我首先需要检查一个元组中的所有类型是否适合解包器并提供相关的错误消息,如果它们不是。

所以代码类似于:

std::tuple

条件template<typename T> struct is_integral_lvalue : std::integral_constant<bool, std::is_lvalue_reference<T>::value && std::is_integral<T>::value && (sizeof(T) == 4 || sizeof(T) == 8)> { }; /* ... */ template<typename TInputBuffer, typename... TDest> static TRet unpack_int_tuple(TInputBuffer src_buf, std::tuple<TDest...> &&dest) noexcept(is_noexcept) { static_assert(typelist::all_are<is_integral_lvalue, TDest...>::value, "All types in a tuple must be integral lvalue-references"); /* do unpacking */ } 可能有点武断。这就是为什么is_integral_constant模板可以使用任何一元谓词的原因。问题是:我应该在all_are中写一下(也许,我应该在上面的代码中解决什么才能编写这样的typelist::all_are)?

一个工作的例子当然是理想的,但如果它们有用,我会很感激一般的想法/建议。

限制我的目标不仅仅是实现这个功能,而是要了解它是如何工作的(像#34这样的解决方案;只需使用boost :: mpl&#34;或者&#34; boost :: hana&#34;不合适)。我们使用的不太相关的东西越多越好。最好是代码应该是C ++ 11(我们还没准备好在生产中使用C ++ 1y / GCC 4.9)。我也希望,可以避免使用预处理器宏。

有些东西,我用Google搜索。当然可以使用Boost.MPL,但它很大,它使用缓慢的递归模板(而不是可变参数)并且很难理解引擎盖下的内容&#34;# 34 ;.不幸的是,Boost :: hana基于多态lambda,它没有进入C ++ 11。我已经看到了这个https://github.com/Manu343726/Turbo库,但它似乎需要在代码中进行太多更改才能使用它(几乎包含其中的所有类型的适配器)。它还使用惰性评估(扩展模板时)等内容 - 这里不需要它,并且会使代码更难阅读。

这个库https://github.com/ldionne/mpl11 几乎我需要的东西。同样问题在于包装器:all_are是作为and_元函数的特殊情况实现的(为了更好的编译时性能而展开它)。并且他们都使用元函数提升,懒惰等等,这使得它很难理解(除非有经验的函数式语言程序员)。那么基本上对我来说就是解释,如何跳过所有那些非常通用和复杂的技术并编写相同的foldr模板,但是以更简单的方式(更具体的用途)。

2 个答案:

答案 0 :(得分:6)

在C ++ 17和fold expressions出现之前,all_of的直接实现是:

// base case; actually only used for empty pack
template<bool... values>
struct all_of : std::true_type {};

// if first is true, check the rest
template<bool... values>
struct all_of<true, values...> : all_of<values...> {};

// if first is false, the whole thing is false
template<bool... values>
struct all_of<false, values...> : std::false_type {}; 

在这种情况下使用成为

static_assert(all_of<is_integral_lvalue<TDest>::value...>::value,
              "All types in a tuple must be integral lvalue-references");

如果您想保留原始语法,请使用别名轻松:

template<template <class> class T, class... U>
using all_are = all_of<T<U>::value...>;

此外,is_integral_lvalue中存在错误 - 参考类型不是整数类型。您的is_integral检查需要typename remove_reference<T>::type而不仅仅是T


修改:这是all_of courtesy of @Columbo的更简单实现:

template<bool...> struct bool_pack;

template<bool...values> struct all_of 
    : std::is_same<bool_pack<values..., true>, bool_pack<true, values...>>{};

答案 1 :(得分:0)

提议and_的非MPL版本为here,现已重命名为conjunction

很久以前,实现是在libstdc ++中(std::__and_中的<type_traits>)。

Here是我更简单的实现(具有不太明确的特化)。