为什么Boost MPL有积分常数?

问题描述 投票:0回答:2

既然可以将整数值作为模板参数并对它们进行算术运算,那么

boost::mpl::int_<>
和其他整数常量背后的动机是什么?这种动机在 C++11 中仍然适用吗?

c++ boost c++11 metaprogramming boost-mpl
2个回答
14
投票

您可以采用整数值作为模板参数,但不能使用单个模板同时采用类型非类型模板参数。长话短说,将非类型模板参数视为类型允许它们与MPL中的无数事物一起使用。

例如,考虑一个元函数

find
,它处理类型并在序列中查找相等的类型。如果您希望将其与非类型模板参数一起使用,则需要重新实现新算法“重载”,即您必须手动指定整数值的
类型
。现在想象一下,您希望它像语言的其余部分一样使用混合积分类型,或者您想要混合类型非类型,您会得到“重载”的爆炸式增长,而这也恰好是更难使用,因为您必须在各处指定每个非类型参数的类型。 这种动机仍然适用于

C++11

这种动机仍然适用于

C++y

和任何其他版本,除非我们有一些新规则允许从 非类型模板参数type 模板参数的转换。例如,每当您使用 find_c 并且模板请求类型时,都会用

5
来实例化它。
    


14
投票

K-Ballo 的回答很棒。

我认为还有其他相关的事情。整型常量类型不仅可用作模板参数,还可用作函数参数和函数返回类型(在我的示例中使用 C++11 类型,但相同的参数适用于早于它们的 Boost 类型):

std::integral_constant< int, 5 >

该函数接受一个函数指针并返回一个类型,告诉您该函数接受的参数数量。在我们拥有 
template<typename R, typename... Args> std::integral_constant<std::size_t, sizeof...(Args)> arity(R (*)(Args...)) { return {}; }

函数之前,无法在常量表达式中调用函数,因此要问诸如“此函数类型需要多少个参数?”之类的问题。您需要返回一个

type
,并从中提取整数值。 即使语言中有

constexpr

(这意味着上面的函数可以只是

constexpr
并且整数值在编译时可用),整型常量类型仍然有很好的用途,例如标签发送:

return sizeof...(Args);

这个 
template<typename T> void frobnicate(T&& t) { frob_impl(std::forward<T>(t), std::is_copy_constructible<T>{}); }

函数可以根据作为第二个参数传递的

frob_impl
类型进行重载:

integer_constant<bool, b>

您可以尝试通过将布尔值设置为模板参数来执行类似的操作:

template<typename T> void frob_impl(T&& t, std::true_type) { // do something } template<typename T> void frob_impl(T&& t, std::false_type) { // do something else }

但不可能部分专门化函数模板,因此您无法使 
frob_impl<std::is_copy_constructible<T>::value>(std::forward<T>(t));

frob_impl<true, T>
做不同的事情。重载布尔常量的
type
可以让您根据“可复制构造”特征的 value 轻松执行不同的操作,并且 that 在 C++11 中仍然非常有用。 常量有用的另一个地方是使用 SFINAE 实现特征。在 C++03 中,传统方法是重载函数,返回两种不同大小的类型(例如

frob_impl<false, T>

和包含两个

int
的结构),并使用
int
测试“值”。在 C++11 中,函数可以返回
sizeof
true_type
,这更具表现力,例如测试“此类型是否有一个名为
false_type
的成员?”的特征可以让表示正结果的函数返回
foo
,让表示负结果的函数返回
true_type
,还有什么比这更清楚的呢?

作为标准库实现者,我

非常

频繁使用false_type

true_type
,因为很多编译时“问题”都有正确/错误的答案,但是当我想测试可以有更多内容的东西时两个不同的结果我将使用
false_type
的其他专业化。
    

© www.soinside.com 2019 - 2024. All rights reserved.