为什么C++11类型特征不是别名模板

Why are C++11 type traits not alias templates?

本文关键字:别名 C++11 类型 特征 为什么      更新时间:2023-10-16

类似的问题:为什么type_traits是用专门的模板结构而不是constexpr实现的但答案不同。

我意识到别名模板不能专门化,因此目前不能直接用于实现类型特征1。然而,这是委员会有意识的决定,据我所见,没有技术上的理由禁止这样做。

那么,将类型特征实现为别名模板,简化它们的语法,难道不是更有意义吗?

考虑

 typename enable_if<is_pointer<T>::value, size_t>::type
 address(T p);

 enable_if<is_pointer<T>, size_t> address(T p);

当然,当从Boost.TypeTraits迁移时,这会带来一个突破性的界面更改——但这真的是一个大问题吗?

毕竟,代码无论如何都需要修改,因为类型位于不同的名称空间中,而且由于许多现代C++程序员不愿意打开名称空间,因此将显式限定(如果要更改的话)。

另一方面,它极大地简化了代码。考虑到模板元编程往往会变得嵌套、复杂和复杂,显然更清晰的界面是有益的。

我是不是错过了什么?如果不是,我希望得到一个不仅仅是猜测,而是依赖于(并且可以引用)对委员会决策理由的了解的答案。


1但是非常好的间接!考虑:

template <typename T> using is_pointer = typename meta::is_pointer<T>::type;

其中,meta::is_pointer<T>对应于当前的std::is_pointer<T>类型。

你的问题最具体的答案是:从来没有人提议过这样做。

C++标准委员会是一个由多个国家、多家公司组成的志愿者团体。你认为它是一个组织内的设计委员会。如果没有在标准草案中添加文字的建议,C++标准委员会实际上什么都做不了。

我想,没有提案的原因是类型特征是一个早期的提案,助推实施可以追溯到2000年左右。模板别名的实现较晚。许多委员会成员不愿意提出一些他们没有实施的建议。而且几乎没有机会实施你的建议。

运送C++11的压力很大。它真的打算在2009年发货,当发货日期推迟时,除了修复已经在考虑的功能外,很难对工作文件做任何事情。在某个时刻,你必须把伟大的新想法放在次要位置,以免你永远无法发货。

更新

从C++14开始,TransformationTraits(导致类型的那些)现在有模板别名拼写,例如:

template <bool b, class T = void>
  using enable_if_t = typename enable_if<b,T>::type;

C++1z工作草案现在有了模板变量拼写,用于产生值的特征:

template <class T>
  constexpr bool is_pointer_v = is_pointer<T>::value;

此外,即使在C++11中也可以做到:

typename enable_if<is_pointer<T>{}, size_t>::type
address(T p);

也就是说,您可以使用{}来代替::value(假设您的编译器支持constexpr)。在C++14中,它变为:

enable_if_t<is_pointer<T>{}, size_t>
address(T p);

在C++1z中:

enable_if_t<is_pointer_v<T>, size_t>
address(T p);

请注意,C++1z和C++14之间的差异非常小,以至于它甚至不保存字符,只是将{}更改为_v,并更改放置这两个字符的位置。

与其他几个库(包括<memory><functional>)一样,类型特征是从C++TR1继承而来的。尽管这是一个不太正式的文档,但它比Boost更正式,兼容性是值得的。

此外,请注意,类型性状都源自std::integral_constant<bool>,它确实实现了constexprbool的转换函数。这样,如果您选择的话,至少可以保存::value零件。

作为一个完整的旁注,因为别名对std::is_pointer:这样的特性的帮助似乎存在混淆

您可以走Boost.MPL路线,并决定使用Boost.MMP类型的积分常数,这意味着类型

template<typename Cond, typename Then = void>
using enable_if = typename std::enable_if<Cond::value, Then>::type;
// usage:
template<
    typename T
    , typename = enable_if<std::is_pointer<T>>
>
size_t address(T p);

或者您可以决定使用值来代替

template<bool Cond, typename Then>
using enable_if = typename std::enable_if<Cond, Then>::type;
// can use ::value
template<
    typename T
    , typename = enable_if<std::is_pointer<T>::value>>
>
size_t address(T p);
// or constexpr conversion operator
template<
    typename T
    , typename = enable_if<std::is_pointer<T> {}>
>
size_t address(T p);

请注意,在后一种情况下,不可能使用enable_if<std::is_pointer<T>()>std::is_pointer<T>()是一种函数类型(采用void并返回std::is_pointer<T>),并且是无效的,因为在这种情况下,我们的别名采用值而不是类型。大括号确保它是一个常量表达式。

正如您可能已经注意到的,std::is_pointer根本没有从模板别名中获益。这并不奇怪,因为有趣的部分是访问::value,而不是::type:模板别名只能帮助处理成员类型。std::is_pointertype成员并不有趣,因为它是Boost.MPL型积分常数(在本例中为std::true_typestd::false_type),所以这对我们没有帮助。对不起!