[英]Const temporary from template type and why use std::add_const?
以下代码摘自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
常量
此外,以下两个陈述之间的区别是什么:
call_m<const foo>();
和
call_m<std::add_const<foo>::type>();
这似乎是MSVC的一个错误。 使用T()
形式的表达式T()
就标准而言,这是一种显式类型转换)会产生指定类型的prvalue。
表达式
T()
,其中T
是非数组完整对象类型的简单类型说明符或类型名称说明 符 ,或者(可能是cv限定的)void
类型,创建指定类型的prvalue,它是值 -初始化
由于非类prvalues不能具有cv限定类型的规则,因此只有非类类型才会忽略const
:
类prvalues可以具有cv限定类型; 非类prvalues始终具有cv不合格类型。
所以这里由T()
创建的临时对象应该是const
,因此应该调用const
成员函数。
至于何时以及为什么要使用std::add_const
,我们可以看看它包含在提案中的原因。 它声明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
表示。
从我记得的内容如下,你可以在函数声明中写出3个consts(3是目的数)。
返回类型之前,函数及其参数之后,以及参数本身。
函数签名末尾的const表示函数应该假定它所属的对象是const。 实际上,它意味着您要求编译器检查成员函数是否以任何方式更改对象数据。 这意味着要求编译器检查它是否不直接更改任何成员数据,并且它不会调用任何本身不保证它不会更改对象的函数。
在返回类型之前意味着函数要返回的东西应该是const。
const参数表示该参数不能更改。
所以区别在于,第一次调用不是const,所以它转到“非cv”,第二次调用是const,因此转到“const”。
我想到为什么VC ++两次都使用相同的函数是call_m显式调用T()。m()认为它不应该转到const。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.