所以我正在浏览http://en.cppreference.com/w/cpp/types/result_of并查看了成员函数result_of
的语法,我只是不明白该decltype的情况。
为什么arg在decltype之后出现?在确定成员函数的类型时,它们不是很重要吗?在我看来,我想象的不是decltype(&C::Func)(C, char, int&)
它应该是decltype(&C::Func(C, char, int&))
或类似的东西,而是我很难绕过它。任何人都可以解释为什么这是这种语法?
答案 0 :(得分:3)
std::result_of
采用F(A...)
形式的模板参数。 F
应该是可调用的类型,例如函数类型或具有重载operator()
的类类型。 A...
应该是一系列参数类型。
因此,如果您有一些表达式e
和一些参数类型A...
,并且您想知道如果使用类型为{{1的参数调用e
,将获得什么结果类型然后你会将A...
= F
放在decltype(e)
中,即std::result_of<F(A...)>
。
答案 1 :(得分:0)
我正在复制您指向的示例中的相关代码:
#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)
是Func
的方法C
的声明类型,它是一个带C
引用的函数(对应this
),{ {1}}和char
参考。int
。T
将是将类型result_of<T(...)>::type
的函数应用于您在括号中指定的类型的参数的结果类型。 T
将为result_of<decltype(&C::Func)(C, char, int&)>::type
。答案 2 :(得分:0)
如您所知,类型T1(T2,T3)
表示函数返回值T1
并使用T2
和T3
类型的参数。只要您处理该类型的值,您就会受到这种解释的束缚。
std::result_of
不处理任何值,只使用T1(T2,T3)
形式的类型,因此从技术上讲,它可以自由地按照自己喜欢的方式解释类型。它实际上做到了!如果std::result_of
将在函数类型上进行参数化,并返回该函数的返回类型,则结果(即嵌套的type
成员)将只是T1
,但它不是'吨。标准编写者选择实现不同的功能:std::result_of
在其类型参数中采用类型T1
而不是要确定的函数的返回类型,但完成一些callable事物的类型(例如函数指针),它将在传递参数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
不能是函数类型,因为禁止描述返回函数的函数的类型。 Case(C)有一个有效的模板参数,其中“function”的返回类型描述了一个可调用的类型,因此std::result_of
是适用的。
考虑到这一背景,您的问题的答案可能很明显。表达式decltype(&C::Func)(C, char, int&)
描述了返回decltype(&C::Func)
并使用参数类型C
,char
和int &
的函数类型。如前所述,返回类型必须是callable,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
(可调用类型)是一个函数对象。通过将函数对象的类型传递给std::result_of
作为T1
,您同时传递该对象的所有函数调用操作符,并且您可以{{1使用重载决策选择正确的一个。无法通过“所有std::result_of
函数”传递“所有Func
函数”,因为operator()
是硬连线的,以便在对象的情况下查找std::result_of
,并且您不能使用address-of运算符将operator()
调用映射到operator()
调用。但是,您可以编写执行此映射的模板:
Func()
模板call_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';
}
上的调用operator()
重定向到基类call_Func<S>
上调用Func(尽管应该使用S
),但请注意你不能写一个“泛型重定向器”,它获取函数的名称以将函数调用操作符重定向为模板参数,因为您既不能将重载集也不能将名称作为模板参数传递,而只能传递类型和常量值(对于非类型参数)。指向成员函数的指针是一种常量值,但是只要形成这样的指针,就已经失去了重载。