const临时从模板类型和为什么使用std :: add_const?

xml*_*lmx 9 c++ overloading type-traits visual-c++ c++11

以下代码摘自cppreference.com.

#include <iostream>
#include <type_traits>

struct foo
{
    void m() { std::cout << "Non-cv\n"; }
    void m() const { std::cout << "Const\n"; }
};

template <class T>
void call_m()
{
    T().m();
}

int main()
{
    call_m<foo>();
    call_m<std::add_const<foo>::type>();
}
Run Code Online (Sandbox Code Playgroud)

但是,使用VC++ 2012年11月的CTP编译时,输出为

非CV

非CV

而不是预期的:

非CV

常量

此外,以下两个陈述之间的区别是什么:

call_m<const foo>();

call_m<std::add_const<foo>::type>();

Jos*_*eld 10

这似乎是MSVC的一个错误.使用表单的表达式T()(就标准而言,这是一种显式类型转换)会产生指定类型的prvalue.

表达式T(),其中是非数组完整对象类型T简单类型说明符类型名称说明,或者(可能是cv限定的)void类型,创建指定类型的prvalue,它是值初始化的

const由于非类prvalues不能具有cv限定类型的规则,因此只有非类类型才会被忽略:

类prvalues可以具有cv限定类型; 非类prvalues始终具有cv不合格类型.

因此,由T()此处创建的临时对象应该const并且应该因此调用const成员函数.

至于您何时以及为何使用std::add_const,我们可以看看它包含在提案中的原因.它指出add_const,add_volatile,add_cv,add_pointer,和add_reference型性状从提案中删除,但随后从加速的投诉用户后恢复.

理由是这些模板都被用作编译时仿函数,它们将一种类型转换为另一种类型[...]

给出的例子是:

// transforms 'tuple<T1,T2,..,Tn>'
// to 'tuple<T1 const&,T2 const&,..,Tn const&>'
template< typename Tuple >
struct tuple_of_refs
{
   // transform tuple element types
   typedef typename mpl::transform<
      typename Tuple::elements,
      add_reference< add_const<_1> > // here!
   >::type refs;
   typedef typename tuple_from_sequence<refs>::type type;
};

template< typename Tuple >
typename tuple_of_refs<Tuple>::type
tuple_ref(Tuple const& t)
{
    return typename tuple_of_refs<Tuple>::type(t);
}
Run Code Online (Sandbox Code Playgroud)

您可以认为mpl::transform将编译时元编程等效于函数指针作为其第二个模板参数 - add_reference<add_const<...>>应用于其中的每个类型Tuple::elements.这根本无法表达const.