<type_traits>
中的某些类型转换也可以使用核心语言语法表示(例如std::add_const<T>::type
/似乎等同于const T
)。 std::add_lvalue_reference
和其他人的Dtto。这些类型特征有什么用?
我完全理解标准会提供一个没有它们的“不完整的工具箱”,我可以想象以元方式使用,如下所示:
template<typename In, template <typename> class Modifier>
struct Apply {
typedef typename Modifier<T>::type Out;
};
Apply<int, std::add_const>
这些特征是否还有其他可以在语法上表达的用例,或者它们是否仅仅是“出于完整感”和偶尔的元使用?
答案 0 :(得分:23)
这些特征来自Boost,并且将其添加到标准中的提议N1345引用Andrei Alexandrescu的话说:
“我理解添加
add_const
,add_volatile
,add_cv
和add_pointer
的对称性论点,不过我会主张删除它们。语言提供等价物更简单,更好。“
同样的提案也提供了这个理由:
作者注:表面上add_const,add_volatile和add_cv类是无关紧要的,因为,例如,对于所有T,add_const :: type与T const相同(目前这不适用于函数类型 - 但是{{3解决这个问题)。然而,来自boost的经验是,有几个用户要求这些模板出现在库中,原因如下:(a)一些用户发现这些模板更明确 - 特别是在组合转换模板时,用户喜欢“内置”类型的用户“这些模板提供的文档”。 (b)并非所有用户都知道允许对引用进行资格认证且无效,或者允许对符合cv资格的类型进行cv认证且无效。 (c)编译器在对作为参考的类型进行资格认证或已经具有cv限定符时可能会发出警告,这些模板可以实施,以便在这些情况下抑制这些消息。
此外,对于add_reference
(在标准中重命名为add_lvalue_reference
):
作者注:add_reference模板是boost类型特征库背后的原始动机之一。但是,issue 295的分辨率使模板显得多余。尽管add_reference可能在无意中在模板代码中创建对引用的引用时抑制编译器警告。
答案 1 :(得分:8)
这些特征是为偶尔的元使用而提供的。它使得在元编程中传输有用的cv限定符成为可能。
template<class T,template<class> class Trait>
struct transform
{
/* working with T creating newT*/
typedef Trait<newT>::type type;
};
template<class T>
struct special_transform
: transfrom<T, std::add_const>
{};
在这种情况下,您无法将std::add_const
替换为const
。
答案 2 :(得分:5)
add_const
可用于解决类型扣减冲突。
template <typename T>
class wrapper;
template <typename T>
bool operator==(wrapper<T> const& w, T const& t);
如果我们使用wrapper<T const>
:
wrapper<int const> w = { 42 };
assert(w == 42); // Error: conflicting deduced types
T
同时推断为int
和 int const
。这可以使用add_const
解决:
template <typename T>
bool operator==(wrapper<T> const& w, add_const_t<T>& t);
答案 3 :(得分:1)
我知道的唯一用例如下所示:
struct F
{
bool f() const { return true; }
bool f() { return false; }
};
assert(!F{}.f())
assert(std::add_const_t< F >{}.f());
它还需要测试 cv-ref-qualified 成员函数功能,这些功能可能因不同的重载而不同(仅适用于lref认证的现代C ++具有方便的std::as_const
功能):
struct F
{
int g() & { return 1; }
int g() const & { return 2; }
int g() && { return 3; }
int g() const && { return 4; }
};
F f;
assert(f.g() == 1);
assert(std::as_const(f).g() == 2);
assert(F{}.g() == 3);
assert(std::add_const_t< F >{}.g() == 4); // rarely needed, but if needed, then it helps