为什么Boost MPL有整数常量?

12
由于您可以将整数值作为模板参数并对其进行算术运算,那么boost::mpl::int_<>和其他整数常量的动机是什么?这个动机在C++11中是否仍然适用?

6
如果您真的对此感兴趣,建议阅读《C++模板元编程》这本书,它由Boost MPL的主要作者撰写,详细解释了这些技术的动机。此外,这不仅适用于C++11,还在C++11中通过std::integral_constant标准化实现。 - Mikael Persson
2个回答

14
简而言之,将值编码为类型可以使其在更多的地方使用,而不仅仅是一个简单的值。您可以对类型进行重载,但无法对值进行重载。
K-Ballo的答案非常好。
还有一些我认为很相关的内容。整数常量类型不仅作为模板参数有用,它们也可以作为函数参数和函数返回类型(在我的示例中使用C++11类型,但相同的论点适用于比它们更早的Boost类型):
template<typename R, typename... Args>
  std::integral_constant<std::size_t, sizeof...(Args)> 
  arity(R (*)(Args...))
  { return {}; }

这个函数接受一个函数指针并返回一个类型,告诉您该函数需要多少参数。在有了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>frob_impl<false, T>执行不同的操作。根据布尔常量的类型进行重载允许您基于“可复制构造”特性的值轻松执行不同的操作,在C++11中仍然非常有用。
常量还可以用于使用SFINAE实现特性。在C++03中,常规方法是具有返回两种不同大小类型(例如一个int和包含两个int的结构体)的重载函数,并使用sizeof测试“值”。在C++11中,函数可以返回true_typefalse_type,这更具表现力,例如,测试“此类型是否具有名为foo的成员?”的特性可以使表示正结果的函数返回true_type,并使表示负结果的函数返回false_type,这有什么比这更清晰的呢?
作为标准库实现者,我经常使用true_typefalse_type,因为很多编译时“问题”都有真/假答案,但是当我想要测试可能有超过两个不同结果的东西时,我会使用integral_constant的其他专门化。

14
你可以将整数值设置为模板参数,但你不能同时将类型和非类型模板参数作为单个模板参数。简而言之,将非类型模板参数视为类型允许它们与MPL中的各种内容一起使用。
例如,考虑一个与类型一起工作并在序列中查找相等类型的元函数find。如果您希望将其用于非类型模板参数,则需要重新实现新算法“重载”,其中必须手动指定整数值的类型。现在想象一下,您想要将其与混合整数类型一起使用,就像语言的其他部分一样,或者您想要混合类型和非类型,您会得到一系列'overloads'的爆炸,也更难使用,因为您必须在每个非类型参数处指定其类型。
这种动机仍然适用于C++11。
除非我们有一些新规则允许从非类型模板参数转换为类型模板参数,否则这种动机仍将适用于C++ y 和任何其他版本。例如,每当您使用5并且模板请求一个类型时,请使用std::integral_constant< int, 5 >来实例化它。

2
C++y?我以为是C++1y? - Andrew Tomazos
你能展示一些代码来说明问题,然后再展示一个可行的版本吗? - Brent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接