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
isfalse\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; }