对这个 decltype 语句实际发生的事情感到困惑
Confusion about what is actually happening with this decltype statement
所以我正在浏览 http://en.cppreference.com/w/cpp/types/result_of 并看到了执行成员函数result_of
的语法,我只是不明白那个 decltype 是怎么回事。
为什么参数在 decltype 之后出现?它们在确定成员函数的类型方面不是很重要吗?在我的脑海里,我想它不应该是decltype(&C::Func)(C, char, int&)
它应该是decltype(&C::Func(C, char, int&))
或类似的东西,但我很难理解它。谁能解释一下为什么是这种语法?
>std::result_of
采用形式为F(A...)
的模板参数。F
应该是可调用的类型,例如函数类型或具有重载operator()
的类类型。A...
应该是参数类型的序列。
因此,如果你有一些表达式e
和一些参数类型A...
,并且你想知道如果你用A...
类型的参数调用e
,你会得到什么结果类型,那么你F
=decltype(e)
放在std::result_of<F(A...)>
中,即std::result_of<decltype(e)(A...)>
。
我正在从您指出的示例中复制相关代码:
#include <type_traits>
struct C {
double Func(char, int&);
};
int main()
{
// result_of can be used with a pointer to member function as follows
std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
static_assert(std::is_same<decltype(g), double>::value, "");
}
decltype(&C::Func)
是C
Func
的声明类型的方法,它是一个接受C
引用(对应于this
)、char
和int
引用的函数。- 我们称这种类型为
T
. - 然后,
result_of<T(...)>::type
将是将类型T
的函数应用于括号中指定其类型的参数的结果的类型。 - 因此,在此示例中,
result_of<decltype(&C::Func)(C, char, int&)>::type
将double
。
如您所知,类型T1(T2,T3)
表示返回值T1
并采用类型T2
和T3
的参数的函数。一旦您使用该类型的值,您就会绑定到该解释。
std::result_of
不处理任何值,只处理T1(T2,T3)
形式的一种类型,因此它在技术上可以自由地以任何它喜欢的方式解释这些类型。它确实如此!如果std::result_of
在函数的类型上参数化,并返回该函数的返回类型,则结果(即嵌套type
成员)将只是T1
,但事实并非如此。标准编写者选择实现不同的功能:std::result_of
在其 type 参数中获取类型T1
不是要确定的函数的返回类型,而是某些可调用事物的完整类型(例如函数指针),它将返回该可调用事物在传递参数T1
和T2
时返回的类型。
示例时间!
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
int main(void)
{
// define the type of a function
typedef int ftype(char, long);
// (A) doesn't compile: you can't call an int
std::cout << typeid(std::result_of<int(char,long)>).name() << 'n';
// (B) doesn't compile: A the return type of a function may not be a function
std::cout << typeid(std::result_of<ftype(char,long)>::type).name() << 'n';
// (C) does compile and print the typeid name of int. On g++ this is "i"
std::cout << typeid(std::result_of<ftype*(char,long)>::type).name() << 'n';
}
案例 (A) 失败,因为int
不可调用,尽管模板参数本身格式正确。案例 (B) 失败,因为模板参数格式不正确。在T1(T2,T3)
中,T1
不能是函数类型,因为描述返回函数的函数的类型是被禁止的。案例 (C) 具有有效的模板参数,其中"函数"的返回类型描述可调用类型,因此std::result_of
适用。
考虑到这种情况,您的问题的答案可能是显而易见的。表达式decltype(&C::Func)(C, char, int&)
描述了返回decltype(&C::Func)
并取参数类型C
、char
和int &
的函数类型。如前所述,返回类型必须是可调用的,decltype(&C::Func)
就是这种情况,因为它是指向成员函数类型的指针double (C::*)(char, int&)
。根据 INVOKE 操作的定义(请参阅有关可调用的页面),此类型是可使用参数列表(C, char, int&)
调用的,因此std::result_of
decltype(&C::Func)(C, char, int&)
的应用程序是有效的。
您建议的替代方案:std::result_of<decltype(&C::Func(C, char, int&))>
无效,因为&C::Func(C, char, int&)
不是有效的表达式。如果要约束类型(以防有多个重载Func
),则可以使用强制转换来实现。decltype(static_cast<double (C::*)(int, char&)>(&C::Func))
是一个有效的表达式,返回(毫不奇怪)类型double (C::*)(int, char&)
。但与示例 (A) 一样,这不是您可以std::result_of
应用的类型。
std::result_of 真正有趣的用例是T1
(可调用类型)是一个函数对象的情况。通过将函数对象的类型作为T1
传递给std::result_of
,您将同时传递该对象的所有函数调用运算符,并且您可以使用重载解析std::result_of
选择正确的运算符。像传递"所有operator()
函数"一样传递"所有Func
函数"是不可能的,因为std::result_of
是硬连线的,可以在对象的情况下查找operator()
,并且不能使用 address-of 运算符将operator()
调用映射到Func()
调用。不过,您可以编写一个模板来执行此映射:
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
class S {
public:
int Func(int);
double Func(float, float);
};
template <typename T>
class call_Func : public T {
public:
template<typename... args>
auto operator()(args... vals) -> decltype(this->Func(vals...)) { return this->Func(vals...); }
};
int main(void)
{
std::cout << typeid(std::result_of<call_Func<S>(int)>::type).name() << 'n';
}
模板call_Func将调用call_Func<S>
operator()
重定向到在基类S
上调用 Func(不过应该使用std::forward
),但请注意,您不能编写一个"通用重定向器"来获取函数的名称以将函数调用运算符重定向到作为模板参数,因为您既不能将重载集或名称作为模板参数传递, 但只是类型和常量值(对于非类型参数)。指针到成员函数是一种常量值,但是一旦形成这样的指针,您就已经丢失了重载。
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- C++decltype和圆括号-为什么
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 如何从"decltype()"获取函数参数的数量<funtion>?
- Confusion: decltype vs std::function
- decltype(1, t) 应该是 l 值引用吗?(编译器不同意)
- 是否可以在不使用 decltype 的情况下推断先前定义的 extern 变量的类型
- 无效 f(int) 的模板和 decltype
- c++ 11 带有 decltype 的尾随返回类型无法按预期工作
- 我可以使用 decltype() 或其他东西通过指针获取真实类型吗?
- decltype:使用指针访问类的静态成员
- decltype() 不适用于正在编译的类模板
- 在部分模板专用化中使用 decltype
- 非静态成员函数的 decltype 格式不正确吗?
- 是否可以使用单个定义定义函数的常量和常规版本?(使用模板,自动,decltype等)
- 使用具有默认参数的函数模板进行 decltype 会使结果混乱(一个有趣的问题或 gcc 的错误)
- "decltype(&ordenary_func)"和"decltype"(ordenary_func)之间的区别
- 指向具有 decltype 的函数的指针向量
- About std::unique_prt() and decltype()
- 来自 decltype 的意外输出类型