鉴于以下声明:
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中使用decltype
或result_of<Mp(const MyClass&&)>::type
,但它们并不能满足我对C ++ 03的需求。有几个人给出了正确的答案,即函数的const rvalue参数不是函数类型的一部分。这为我澄清了一些事情,我将实现我的前C ++ 11 result_of
,这样它也会丢弃这些限定符。
答案 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>
的所有参数都是参考。