result_of具有 cv 限定参数的成员对象
result_of for member object with cv-qualified argument
给定以下声明:
struct MyClass { };
typedef int MyClass::*Mp;
在我尝试过的 gcc 6.2 和 Clang 编译器上,result_of<Mp(const MyClass)>::type
产生int&&
.
我的问题摘要:为什么int&&
而不是const int&&
或只是int
?
更多背景:该标准说result_of
是这样定义的:
成员类型定义类型应命名类型
decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));
该标准还以这种方式定义了指向成员对象的指针调用:
— 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 中需要的功能。 有几个人给出了正确的答案,即函数的常量值参数不是函数类型的一部分。 这为我澄清了事情,我将实施我的 C++11 之前result_of
,以便它也丢弃这些限定符。
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 限定符在形成 函数类型。转换后的参数类型的结果列表和 是否存在省略号或函数参数包 是函数的参数类型列表。[ 注意:此转换 不影响参数的类型。例如,
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>()...));
};
这个定义实际上是标准应该使用的。
在result_of_t<Mp(const MyClass)>
中,您似乎试图询问使用类型 MyClass
的 const
右值调用Mp
的结果类型是什么。用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
的所有参数都是引用。
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 如何使用Visual Studio 2017在C++中为参数化对象数组使用唯一指针
- Arduino C++在构造函数中用参数声明对象数组
- 在运行时有条件地删除类成员或跳过调用该成员对象的构造函数
- 如何编写将展开以定义具有模板参数的对象的宏
- C++类对象 - 遍历基于参数的对象
- 绑定到可变参数成员函数
- 构造函数中没有参数的对象类成员按什么顺序初始化?
- C++是否有定义的方法来传递指向类的成员对象的成员函数的指针
- (2 问题)"类"类型重新定义(即使 #pragma 一次),以及静态函数内的静态成员对象初始化?
- 声明成员对象而不调用其默认构造函数
- 当我按值传递参数时对象被破坏时?
- C++具有内置缓存 - 阴影模板参数的对象工厂
- C/C++ 包含点的宏参数(成员访问运算符)
- 指向成员对象的指针 - 中断线程
- 错误 C2512:没有可用的适当默认构造函数:在构造函数中声明带有参数的对象!
- 初始化具有参数的类成员对象的正确方法
- 如何初始化需要派生类中的构造函数参数的成员对象
- 使用指针成员对象的指针成员作为函数的参数
- result_of具有 cv 限定参数的成员对象