假设我想为整数类型而不是字符做一些事情,我有
is_integral<T>::type
和is_char<T>::type
是否可以这样写:
integral_constant<bool,is::integral<T>::value && !is_char<T>::value>
更具可读性
这些元计算甚至在 C++11 之前就已经完成,而Boost.MPL是 C++03 中 TMP 的重炮。有了它,您的要求可以这样表达:
// in C++03:
// typedef /* compute */ result;
using result = and_<is_integral<T>, not_<is_char<T>>>;
(来自命名空间的位置and_
和位置。)not_
boost::mpl
请注意有限的冗长,因为您不必使用::value
样板。同样,result
它是惰性的,您可以在其中强制使用result::value
(将是true
or false
)或result::type
(这将是一个类型——文档包含所有详细信息)来强制计算结果。Boost.MPL 很容易不这样做,因此例如not_<result>
足以反转逻辑,即使not_<result::type>
也可以工作。typename
考虑到如果依赖,则需要附加项是一件好事result
。
我确实认为 Boost.MPL 在 C++03 中有巨大帮助,部分原因是它模拟了可变参数模板。例如,and_
不限于两个参数。我在 C++11 中避开了它,但是因为在我使用它的大多数情况下,我现在使用包扩展。尽管如此,类似的东西and_
仍然有用,因为不可能在任意表达式中扩展包,例如在涉及&&
逻辑运算符的表达式中。这只能通过逻辑元函数来完成:
// Enforce precondition: every type T must be integral
static_assert( and_<std::is_integral<T>...>::value, "Violation" );
我认为这篇文章是一本很好的读物,它给出了减少元计算冗长的很好的提示。它侧重于用于通用编程的 SFINAE,但它也适用于 TMP(SFINAE 也可用于 TMP)。最后一个例子是
template <typename T,
EnableIf<is_scalable<T>, is_something_else<T>>...>
T twice(T t) { return 2*t; }
在 C++03 中可能看起来像这样,使用类似于 Boost 中提供的工具:
template<typename T>
typename enable_if<
and_<is_scalable<T>, is_something_else<T>>
, T
>::type twice(T t) { return 2*t; }
一个天真的 C++11 版本可以说是最糟糕的:
template<typename T>
typename std::enable_if<
is_scalable<T>::value && is_something_else<T>::value
, T
>::type twice(T t) { return 2*t; }
我见过一些主张放弃 Boost.MPL 风格的人,Boost.MPL 倾向于使用类型和类型“返回”元函数来使用值和constexpr
函数。这可能看起来像:
// EnableIf alias now accepts non-type template parameters
template<typename T
, EnableIf<is_scalable<T>() && is_something_else<T>()>...>
T twice(T t) { return 2*t; }
你仍然需要一个constexpr
函数来计算例如逻辑析取如果T...
是一个包虽然:EnableIf<any(is_foo<T>()...)>
.
为什么需要积分常数?如果您只需要一个编译时常量 bool,那么您不必包装表达式。
is_integral<T>::value && !is_char<T>::value
如果你在几个地方需要这个表达式,你可以写你自己的特殊类型特征。
template<typename T>
struct is_integral_and_not_char {
static const bool value = is_integral<T>::value && !is_char<T>::value;
};
is_integral_and_not_char<T>::value
或者,如果您确实想符合 UnaryTypeTrait 概念,那么
template<typename T>
struct is_integral_and_not_char
: std::integral_constant<bool, std::is_integral<T>::value && !std::is_char<T>::value>
{}