具有cv限定参数

时间:2016-08-28 00:07:58

标签: c++ c++14 language-lawyer result-of

鉴于以下声明:

struct MyClass { };
typedef int MyClass::*Mp;

在我尝试的gcc 6.2和Clang编译器上,result_of<Mp(const MyClass)>::type产生int&&

我的问题摘要:为什么int&&而不是const int&&或只是int

更多背景:标准说result_of是这样定义的:

  

成员typedef类型应为该类型命名   decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));

该标准还以这种方式为指针指向成员对象定义了INVOKE:

  

- t1。* f当N == 1且f是指向T类数据成员的指针且is_base_of_v<T, decay_t<decltype(t1)>>为真时;

请注意,decay_t仅用于测试此项目是否适用。据我所知,应用上述两点应该产生:

decltype(declval<const MyClass>().*declval<Mp>())

产生const int&&。那么,我错过了什么,还是编译器库错了?

编辑,2016年8月30日:

感谢您的回复。有些人建议在不使用result_of的情况下获得正确结果的替代方法。我应该澄清一下,我对result_of的正确定义感到困惑的原因是,我实际上实现了与{C ++ 11之前的编译器一起使用的result_of最接近的合理实现。因此,虽然我同意我可以在C ++ 11中使用decltyperesult_of<Mp(const MyClass&&)>::type,但它们并不能满足我对C ++ 03的需求。有几个人给出了正确的答案,即函数的const rvalue参数不是函数类型的一部分。这为我澄清了一些事情,我将实现我的前C ++ 11 result_of,这样它也会丢弃这些限定符。

2 个答案:

答案 0 :(得分:8)

const将从函数参数中删除。您可以使用is_same验证这一点。

void(int) == void(const int)
Mp(MyClass) == Mp(const MyClass)
result_of<Mp(MyClass)> == result_of<Mp(const MyClass)>

我认为[8.3.5.5]解释了这一点:

  

生成参数类型列表后,任何顶级   修改参数类型的cv-qualifiers在形成时删除   功能类型。生成的转换参数类型列表和   是否存在省略号或函数参数包   是函数的参数类型列表。 [注意:这种转变   不会影响参数的类型。例如,int(*)(const int p, decltype(p)*)int(*)(int, const int*)是相同的类型。    - 结束说明]

您可以通过定义自己的result_of来解决这个问题,而template <typename F, typename... ArgTypes> struct my_result_of { using type = decltype(std::invoke(std::declval<F>(), std::declval<ArgTypes>()...)); }; 不会(错误地)使用函数类型:

{{1}}

这个定义实际上是标准应该使用的。

答案 1 :(得分:5)

result_of_t<Mp(const MyClass)>中,您似乎试图询问使用Mp const类型MyClass的{​​{1}}来调用result_of的结果类型。使用result_of_t<Mp(const MyClass&&)>提出问题的更好方法是decltype,但通常更容易使用result_of并忘记const曾经存在过。如果您确实打算使用result_of_t<Mp(const MyClass&)>左值来询问结果,那么这将是const

函数参数中的顶级result_of确实在函数声明中没有意义。因此,当使用const时,提供参数类型作为对可能 - print_type类型的引用更有意义。这也使得价值类别明确,不会失去表现力。我们可以使用template <typename...> struct print_type; // forward declaration print_type<std::result_of_t<Mp(const MyClass)>, std::result_of_t<Mp(const MyClass&)>, std::result_of_t<Mp(const MyClass&&)>, std::result_of_t<Mp(MyClass)>, std::result_of_t<Mp(MyClass&)>, std::result_of_t<Mp(MyClass&&)>>{}; 技巧来查看执行此操作时会发生什么:

error: invalid use of incomplete type 'struct print_type<int&&, const int&, const int&&, int&&, int&, int&&>'

打印:

std::result_of_t<Mp(const MyClass)>   == int&&
std::result_of_t<Mp(const MyClass&)>  == const int&
std::result_of_t<Mp(const MyClass&&)> == const int&&
std::result_of_t<Mp(MyClass)>         == int&&
std::result_of_t<Mp(MyClass&)>        == int&
std::result_of_t<Mp(MyClass&&)>       == int&&

所以我们可以推断:

result_of_t<Mp(const MyClass)>

我们可以看到result_of_t<Mp(MyClass)>result_of_t<Mp(MyClass&&)>declval都意味着相同的事情。如果他们不这样做,我会觉得很惊讶。

请注意,当您使用declval时,您还提供参数类型作为引用,因为std::invoke被声明为返回引用。此外,<script> setInterval(function () { var newCount = '@(new ShipperHN.DAO.PostDAO().getTotalPost())'; var curCount = '@Session["curCount"]'; alert(newCount +"\t"+ curCount); if (newCount > curCount) { document.getElementById("checkNewPosts").innerHTML = (newCount - curCount) + " new posts unread"; } }, 2000); </script> 的所有参数都是参考。