以下代码摘自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>();
答案 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_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 :(得分:-1)
从我记得的内容如下,你可以在函数声明中写出3个consts(3是目的数)。
返回类型之前,函数及其参数之后,以及参数本身。
函数签名末尾的const意味着函数应该假定它所属的对象是const。实际上,它意味着您要求编译器检查成员函数是否以任何方式更改对象数据。这意味着要求编译器检查它是否没有直接更改任何成员数据,并且它不会调用任何本身并不能保证它不会更改对象的函数。
返回类型之前的表示函数要返回的东西应该是const。
const参数表示该参数无法更改。
所以区别在于,第一次调用不是const,所以它转到&#34;非cv&#34;,第二次调用是const,因此转到&#34; const&#34;
我想到为什么VC ++两次都使用相同的函数是因为call_m显式地调用了T()。m()认为它不应该转到const。