2013-02-28 23 views
9

以下代码摘自cppreference.com从模板类型const临时变量,为什么使用std :: add_const?

#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

常量

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

call_m<const foo>();

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

+6

最有可能的错误,按预期在gcc中工作... – Nim 2013-02-28 12:46:41

回答

10

这似乎是MSVC的错误。使用表达式T()(这是显式类型转换,就标准而言)将导致指定类型的前值。

表达T(),其中T简单型说明符或用于非阵列的完整对象类型或(可能CV修饰)void类型名说明符,创建的prvalue指定的类型,这是值初始化

只有与该const将被忽略非类类型,由于非类prvalues不能有CV-限定类型的规则:

类prvalues可以有cv限定类型;非职业价值总是有cv不合格的类型。

因此,通过T()这里创建的临时对象应该是const,因此应该调用const成员函数。我们可以看看the proposal中包含的原因。它指出,add_const,add_volatile,add_cv,add_pointer,add_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

从我记得它如下,你可以在函数声明中编写3个常量(3是目的数)。

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

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

返回类型之前表示函数返回的东西应该是一个常量。

常量参数表示参数无法更改。

所以这里的区别是,第一个调用不是const,所以它转到“非cv”,第二个调用是const,因此转到“const”。

我认为VC++为什么两次同时使用同一个函数的原因是,call_m显式地调用T().m(),认为它不应该转到const函数。

相关问题