C++ 为什么用专门的模板结构而不是constexpr实现type_特性?

C++ 为什么用专门的模板结构而不是constexpr实现type_特性?,c++,c++11,template-meta-programming,typetraits,C++,C++11,Template Meta Programming,Typetraits,标准是否有理由将它们指定为模板structs而不是简单的布尔值constepr 另外一个问题很可能是对主要问题的一个很好的回答,如果使用非结构化版本填充,那么如何启用\u?可能是因为boost已经有了一个使用模板实现的类型\u traits版本 我们都知道标准委员会有多少人复制boost。一个原因是constepr函数不能提供嵌套的类型成员,这在某些元编程情况下很有用 为了说明这一点,我并不仅仅是在谈论产生类型的转换特性(比如make_unsigned),显然不能使其成为constepr函数。所

标准是否有理由将它们指定为模板
struct
s而不是简单的布尔值
constepr


另外一个问题很可能是对主要问题的一个很好的回答,如果
使用非结构化版本填充,那么如何启用\u?

可能是因为boost已经有了一个使用模板实现的类型\u traits版本


我们都知道标准委员会有多少人复制boost。

一个原因是
constepr
函数不能提供嵌套的
类型
成员,这在某些元编程情况下很有用

为了说明这一点,我并不仅仅是在谈论产生类型的转换特性(比如
make_unsigned
),显然不能使其成为
constepr
函数。所有类型特征都提供这样一个嵌套的
类型
成员,甚至一元类型特征和二元类型特征。例如
is\u void::type
is
false\u type

当然,这可以通过
std::integral_constant
来解决,但它并不实用

在任何情况下,如果您真的想要类似函数的语法,这已经是可能的了。您只需使用traits构造函数并利用:

static_断言(std::is_void(),“void is void;谁会这么做?”;
对于转换特性,您可以使用模板别名获得与该语法相近的内容:

template <bool Condition, typename T = void>
using enable_if = typename std::enable_if<Condition, T>::type;
// usage:
// template <typename T> enable_if<is_void<T>(), int> f();
//
// make_unsigned<T> x;
模板
使用enable_if=typename std::enable_if::type;
//用法:
//模板启用_if f();
//
//使_成为无符号x;

一个原因是,type_traits提案比constexpr提案旧


另一个原因是,如果需要,您可以为自己的类型添加专门化。

我想说的主要原因是
type\u traits
已经是
tr1
的一部分,因此基本上保证以或多或少相同的形式出现在标准中,因此它早于
constepr
。其他可能的原因包括:

  • 将trait作为类型允许重载trait类型上的函数
  • 许多特征(如
    删除\u指针
    )定义了
    类型
    ,而不是
    ,因此它们必须以这种方式表示。为定义值的特征和定义类型的特征提供不同的接口似乎没有必要
  • 模板化结构
    可以部分专门化,而函数不能,因此可能会使某些特性的实现更容易
关于你的第二个问题:如果
定义了
类型
(或者没有,如果传递为false),那么
结构
中的嵌套typedef实际上是一种方法注意:这看起来更像是一种咆哮,而不是一个正确的答案。。。不过,读了前面的答案,我确实有些痒,所以请原谅;)

首先,类特征在历史上是通过模板结构完成的,因为它们早于
constepr
decltype
。如果没有这两个函数,使用函数的工作量会大一些,尽管
的各种库实现都是
在内部使用函数以获得正确的继承

使用函数的优点是什么

  • 继承就行了
  • 语法可以更自然(
    typename::type
    TM)
  • 许多特征现在已经过时了
实际上,继承可能是反对类特征的主要观点。要像momma那样专门化所有的派生类,真是让人恼火。很烦人。使用函数时,您只需继承特性,如果愿意,还可以进行专门化

的缺点是什么

  • 包装!一个结构特征可以同时嵌入多个类型/常量
当然,有人可能会说这实际上很烦人:专门化
iterator\u traits
,你经常无偿地继承
std::iterator\u traits
,只是为了得到默认值。不同的功能会自然而然地提供这一点

它能工作吗

好的,在一句话中,所有内容都是基于
constepr
的,除了
enable\u if
(但是,这不是一个特征),您将:

template <typename T>
typename enable_if<std::is_integral(T()) and
                   std::is_signed(T())>::type
如果我需要一个类型,而不是一个常量呢

什么!骗子!没有定义特征

哼。。。事实上,这就是重点。有了
decltype
,很多特征就变得多余了

干燥

继承就行了

以基本类层次结构为例:

struct Base {};
struct Derived: Base {};
struct Rederived: Derived {};
并定义一个特征:

// class version
template <typename T>
struct some_trait: std::false_type {};

template <>
struct some_trait<Base>: std::true_type {};

template <>
struct some_trait<Derived>: some_trait<Base> {}; // to inherit behavior

template <>
struct some_trait<Rederived>: some_trait<Derived> {};
注意:省略号的使用是有意的,这是一个包罗万象的重载。模板函数比其他重载(不需要转换)更匹配,而省略号总是最差的匹配,保证它只选择那些不适合其他重载的函数

我想没有必要精确说明后一种方法有多简洁?您不仅可以摆脱
模板
混乱,还可以免费获得继承

如果
可以实现,那么
可以启用吗

不幸的是,我不这么认为,但正如我已经说过的:这不是一种特质。而
std
版本与
constepr
配合得很好,因为它使用了
bool
参数,而不是类型:)

那么为什么

唯一的技术原因是,代码的大部分已经依赖于历史上作为类型提供的许多特性(
std::numeric\u limit
),因此一致性将决定它

此外,它使从
boost::is*
的迁移变得非常简单

我个人认为这是不幸的。但是
decltype(common_type(std::declval<T>(), std::declval<U>()))
// class version
template <typename Container>
struct iterator { typedef typename Container::iterator type; };

template <typename Container>
struct iterator<Container const> {
  typedef typename Container::const_iterator type;
};

template <typename Container>
struct pointer_type {
  typedef typename iterator<Container>::type::pointer_type type;
};


template <typename Container>
typename pointer_type<Container>::type front(Container& c);

// Here, have a cookie and a glass of milk for reading so far, good boy!
// Don't worry, the worse is behind you.


// function version
template <typename Container>
auto front(Container& c) -> decltype(*begin(c));
struct Base {};
struct Derived: Base {};
struct Rederived: Derived {};
// class version
template <typename T>
struct some_trait: std::false_type {};

template <>
struct some_trait<Base>: std::true_type {};

template <>
struct some_trait<Derived>: some_trait<Base> {}; // to inherit behavior

template <>
struct some_trait<Rederived>: some_trait<Derived> {};
// function version
constexpr bool some_trait(...) { return false; }

constexpr bool some_trait(Base const&) { return true; }