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

时间:2013-02-28 12:43:04

标签: c++ visual-c++ c++11 overloading typetraits

以下代码摘自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>();
}

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

  

非CV

     

非CV

而非预期:

  

非cv

     

CONST

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

call_m<const foo>();

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

2 个答案:

答案 0 :(得分:10)

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

  

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

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

  

类prvalues可以具有cv限定类型;非类prvalue总是有cv不合格的类型。

因此T()创建的临时对象应为const,因此应调用const成员函数。

至于何时以及为何使用std::add_const,我们可以看看the proposal中包含它的原因。它指出add_constadd_volatileadd_cvadd_pointeradd_reference类型特征已从提案中删除,但在Boost用户投诉后恢复

  

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

给出的例子是:

// 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);
}

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

答案 1 :(得分:-1)

从我记得的内容如下,你可以在函数声明中写出3个consts(3是目的数)。

返回类型之前,函数及其参数之后,以及参数本身。

函数签名末尾的

const意味着函数应该假定它所属的对象是const。实际上,它意味着您要求编译器检查成员函数是否以任何方式更改对象数据。这意味着要求编译器检查它是否没有直接更改任何成员数据,并且它不会调用任何本身并不能保证它不会更改对象的函数。

返回类型之前的

表示函数要返回的东西应该是const。

const参数表示该参数无法更改。

所以区别在于,第一次调用不是const,所以它转到&#34;非cv&#34;,第二次调用是const,因此转到&#34; const&#34;

我想到为什么VC ++两次都使用相同的函数是因为call_m显式地调用了T()。m()认为它不应该转到const。