9

以下代码摘自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++ Nov 2012 CTP 编译时,输出为

非简历

非简历

而不是预期的:

非简历

常量

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

call_m<const foo>();

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

4

2 回答 2

10

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

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

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

类纯右值可以有 cv 限定类型;非类纯右值始终具有 cv 非限定类型。

所以T()这里创建的临时对象应该const也应该调用const成员函数。

至于你什么时候用,为什么用std::add_const,我们可以看一下它被列入提案的原因。它指出 , add_const, add_volatile,add_cvadd_pointertypeadd_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.

于 2013-02-28T13:09:00.890 回答
-1

根据我的记忆,您可以在函数声明中编写 3 个 consts(3 是目的数)。

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

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

在返回类型之前意味着函数要返回的东西应该是一个常量。

const 参数表示该参数不能更改。

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

我认为为什么 VC++ 两次都使用同一个函数是 call_m 显式调用 T().m() 认为它不应该使用 const 函数。

于 2013-02-28T13:19:16.233 回答