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
是这样定义的:
the member typedef type shall name the type
decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));
该标准还以这种方式为指向成员对象的指针定义了 INVOKE:
— t1.*f when N == 1 and f is a pointer to data member of a class T and is_base_of_v<T, decay_t<decltype(t1)>>
is true;
请注意,decay_t
仅用于测试此项目符号是否适用。据我所知,应用以上两点应该会产生:
decltype(declval<const MyClass>().*declval<Mp>())
产生 const int&&
。那么,是我遗漏了什么,还是编译器库有误?
编辑,2016 年 8 月 30 日:
感谢您的回复。一些人提出了不使用 result_of
获得正确结果的替代方法。我应该澄清,我对 result_of
的正确定义挂断的原因是我实际上正在实现最接近合理的 result_of
实现,它适用于 C++11 之前的编译器。因此,虽然我同意我可以在 C++11 中使用 decltype
或 result_of<Mp(const MyClass&&)>::type
,但它们并不能满足我对 C++03 的需求。几个人给出了正确的答案,即函数的 const 右值参数不是函数类型的一部分。这为我澄清了一些事情,我将实施我的 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]
解释的:
After producing the list of parameter types, any top-level
cv-qualifiers modifying a parameter type are deleted when forming the
function type. The resulting list of transformed parameter types and
the presence or absence of the ellipsis or a function parameter pack
is the function’s parameter-type-list. [ Note: This transformation
does not affect the types of the parameters. For example, int(*)(const
int p, decltype(p)*)
and int(*)(int, const int*)
are identical types.
— end note ]
您可以通过定义自己的 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
被声明为 return 引用。此外,std::invoke
的所有参数都是引用。
给定以下声明:
struct MyClass { };
typedef int MyClass::*Mp;
在我试过的 gcc 6.2 和 Clang 编译器上,result_of<Mp(const MyClass)>::type
产生 int&&
.
我的问题总结: 为什么是 int&&
而不是 const int&&
或者只是 int
?
更多背景:标准说 result_of
是这样定义的:
the member typedef type shall name the type
decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));
该标准还以这种方式为指向成员对象的指针定义了 INVOKE:
— t1.*f when N == 1 and f is a pointer to data member of a class T and
is_base_of_v<T, decay_t<decltype(t1)>>
is true;
请注意,decay_t
仅用于测试此项目符号是否适用。据我所知,应用以上两点应该会产生:
decltype(declval<const MyClass>().*declval<Mp>())
产生 const int&&
。那么,是我遗漏了什么,还是编译器库有误?
编辑,2016 年 8 月 30 日:
感谢您的回复。一些人提出了不使用 result_of
获得正确结果的替代方法。我应该澄清,我对 result_of
的正确定义挂断的原因是我实际上正在实现最接近合理的 result_of
实现,它适用于 C++11 之前的编译器。因此,虽然我同意我可以在 C++11 中使用 decltype
或 result_of<Mp(const MyClass&&)>::type
,但它们并不能满足我对 C++03 的需求。几个人给出了正确的答案,即函数的 const 右值参数不是函数类型的一部分。这为我澄清了一些事情,我将实施我的 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]
解释的:
After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function’s parameter-type-list. [ Note: This transformation does not affect the types of the parameters. For example,
int(*)(const int p, decltype(p)*)
andint(*)(int, const int*)
are identical types. — end note ]
您可以通过定义自己的 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
被声明为 return 引用。此外,std::invoke
的所有参数都是引用。