std::add_const和类似功能的使用案例

28
一些在<type_traits>中的类型转换也可以用核心语言语法来表达(例如,std::add_const<T>::type 等同于 const T)。std::add_lvalue_reference等其他类型特性也是如此。这些类型特性有什么作用呢?
如果没有它们,标准就会提供一个“不完整的工具箱”。我可以想象以元方式使用它们的情况,类似于这样的东西:
template<typename In, template <typename> class Modifier>
struct Apply {
  typedef typename Modifier<T>::type Out;
};

Apply<int, std::add_const>

这些特征还有哪些能够通过语法表达的用例,或者它们只是为了完整性和偶尔的元用途而被包含在内?

1
如果 T 已经是 const,会发生什么? - Peter Wood
1
@PeterWood 这个链接 在gcc 4.7.2中至少运行良好。 - Angew is no longer proud of SO
3
如果已经符合资格要求,它会按照标准所要求的返回相同类型。 - jrok
2
std::add_{l,r}value_reference 的原因是 void 会对一个简单的 T&T&& 报错,因为你不能形成一个对 void 的引用。至于 add_const,我只能想到它的对称性。 - Xeo
1
关于 add_const,还请参考这个问答 - Andy Prowl
显示剩余2条评论
4个回答

23
那些特性来自于Boost以及将它们添加到标准中的提案N1345,引用了Andrei Alexandrescu的话:
“我理解为什么要添加add_constadd_volatileadd_cvadd_pointer这些对称性论点,但我会主张将它们删除。语言提供的等效物更简单、更好。”
同一提案还给出了这个原因:
作者注:从表面上看,add_const、add_volatile和add_cv类并不相关,例如add_const::type对于所有T都与T const相同(目前这不适用于函数类型,但issue 295解决了这个问题)。然而,从boost的经验来看,一些用户要求在库中提供这些模板,原因如下:(a)有些用户发现这些模板更加明确——特别是在组合转换模板时,用户喜欢这些模板提供的“内置文档”形式。(b)并非所有用户都知道cv限定引用是被允许且没有影响的,或者将已经cv限定的类型再次进行cv限定是被允许且没有影响的。(c)编译器可能会在对引用类型或已经有cv限定符的类型进行cv限定时发出警告,在这些情况下,可以实现这些模板以抑制这些消息。

此外,对于add_reference(在标准中更名为add_lvalue_reference):

作者注:add_reference模板是boost类型特征库的最初动机之一。然而,问题106的解决方案使得该模板似乎大部分都是多余的。尽管如此,在模板代码中无意中创建引用引用时,add_reference可能非常有用,可以抑制编译器警告。

5
add_{l,r}value_reference 函数对 void 类型的处理也很好。 - Xeo

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>
{};

在这种情况下,您不能用const替换std::add_const

在这种情况下,你不会这样做,因为你已经特别设计它与类型特征一起使用。但是,如果你传递const T代替std::add_const,完全删除第二个模板参数呢?我相信在这种情况下它会起作用。 - KeyC0de

7

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 被同时推断为 intint const。可以使用 add_const 来解决:

template <typename T>
bool operator==(wrapper<T> const& w, add_const_t<T>& t);

1
有趣的用例。任何使第二个函数参数成为非推导上下文的东西也可以,但这个相当简洁。 - Angew is no longer proud of SO

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-qualified的现代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

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