如何在模板化函数指针声明中读取这么多星号和括号?
How to read so many stars and parentheses in a templated function-pointer declaration?
来自Introduction to the C++11 feature: trailing return types
文章声称
template <class T> class tmp {
public:
int i;
};
auto foo()->auto(*)()->tmp<int>(*)(){
return 0;
}
等同于
template <class T> class tmp{
public:
int i;
};
tmp<int> (*(*foo())())() {
return 0;
}
我不明白第二个代码示例中的复杂功能。一开始应该看哪里?我猜是foo
。但是 foo
旁边的统计数据将把 foo
定义为指针...
基于第一个代码示例,我将片段转换为
tmp<int> (*)() (*)() foo(){ return 0;}
所以 foo 是一个函数,returns 0,但是 return 类型很棘手:它的 return 类型是函数指针,其 return 类型又是return 类型为 tmp<int>
.
的函数指针
cdecl 是一个有用的在线工具,可以揭开复杂的 C 声明的神秘面纱。
正在插入 int (*(*foo())())()
returns:
declare foo as function returning pointer to function returning pointer to function returning int
我已将 tmp<int>
替换为 int
,因为该工具不支持模板。
Where should I look at in the beginning?
老实说,你应该看看 https://cdecl.org/,它把 int (*(*foo())())();
描述为:
declare foo as function returning pointer to function returning pointer to function returning int
然后意识到这是 C++11,我们有一个非常好的声明函数指针别名的语法:
using A = int(*)(); // pointer to function returning int
using B = A(*)(); // pointer to function returning pointer to function returning int
B foo(); // function returning pointer to function returning pointer to function returning int
今天真的没有理由写这样的声明。
正确格式化代码可能有助于您理解:
template <class T>
class tmp {
public:
int i;
};
auto foo() -> auto(*)() -> tmp<int>(*)() {
return 0;
}
template <class T>
class tmp{
public:
int i;
};
tmp<int> (*
( *foo() )()
)() {
return 0;
}
template class
部分保持不变,因此我不打算对其进行详细说明。让我们看看函数 foo
.
在第一个代码中,foo()
的return值是auto(*)() -> tmp<int>(*)()
,这是一个指向函数的指针return另一个指针,它指向一个函数 returning tmp<int>
.
因为您总是可以定义函数指针,例如:
base_type_t (*pointer_name)(parameter_list);
用一个函数(即func_name()
)递归pointer_name
可以声明一个函数,其return值是这样一个指针:
base_type_t (*func_name())(parameter_list);
~~~~~~~~~~~
所以现在(*func_name())(parameter_list)
可以起到另一个作用了。让我们把它放回到函数指针定义语法中:
base_type_t (*(*func_name())(parameter_list))(parameter_list);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
清除参数列表(它们是空的)并用正确的类型替换标识符给出:
base_type_t (*(*func_name())(parameter_list))(parameter_list);
tmp<int> (*(* foo ())( /* Empty */ ))( /* Empty */ );
// Turns to
tmp<int> (*(*foo())())();
正如其他人已经建议的那样,https://cdecl.org/ 是一个很好的代码分析器,尽管它可能会给您另一个不太容易理解的句子。
作为对@Vittorio 答案的补充,Clockwise Spiral Rule 可以帮助我们破译复杂类型:
从未知元素开始,向spiral/clockwise方向移动;遇到以下元素时用对应的英文语句替换:
[X]
或 []
Array X
size of... or Array undefined size of...
(type1, type2)
Function passing type1 and type2 returning...
*
pointer(s) to...
在 spiral/clockwise 方向继续这样做,直到所有标记都被覆盖。始终首先解决括号中的任何问题!
这里:
+-----------+
| +------+ |
| | >-v | |
temp<int> (*(*foo())())()
| | ^---+ | |
| ^--------+ |
+--------------+
foo
是一个函数,返回一个指向函数的指针,返回一个指向函数的指针,返回一个temp<int>
。
现在,@UKmonkey 刚刚将此规则重命名为 C++ Guru Snail 规则 或简称 CGSR:
/ /
L_L_
/ \
|00 | _______
|_/ | / ___ \
| | / / \ \
| |_____\ \_ / /
\ \____/ /_____
\ _______________/______\.............................
来自Introduction to the C++11 feature: trailing return types
文章声称
template <class T> class tmp {
public:
int i;
};
auto foo()->auto(*)()->tmp<int>(*)(){
return 0;
}
等同于
template <class T> class tmp{
public:
int i;
};
tmp<int> (*(*foo())())() {
return 0;
}
我不明白第二个代码示例中的复杂功能。一开始应该看哪里?我猜是foo
。但是 foo
旁边的统计数据将把 foo
定义为指针...
基于第一个代码示例,我将片段转换为
tmp<int> (*)() (*)() foo(){ return 0;}
所以 foo 是一个函数,returns 0,但是 return 类型很棘手:它的 return 类型是函数指针,其 return 类型又是return 类型为 tmp<int>
.
cdecl 是一个有用的在线工具,可以揭开复杂的 C 声明的神秘面纱。
正在插入 int (*(*foo())())()
returns:
declare foo as function returning pointer to function returning pointer to function returning int
我已将 tmp<int>
替换为 int
,因为该工具不支持模板。
Where should I look at in the beginning?
老实说,你应该看看 https://cdecl.org/,它把 int (*(*foo())())();
描述为:
declare foo as function returning pointer to function returning pointer to function returning int
然后意识到这是 C++11,我们有一个非常好的声明函数指针别名的语法:
using A = int(*)(); // pointer to function returning int
using B = A(*)(); // pointer to function returning pointer to function returning int
B foo(); // function returning pointer to function returning pointer to function returning int
今天真的没有理由写这样的声明。
正确格式化代码可能有助于您理解:
template <class T>
class tmp {
public:
int i;
};
auto foo() -> auto(*)() -> tmp<int>(*)() {
return 0;
}
template <class T>
class tmp{
public:
int i;
};
tmp<int> (*
( *foo() )()
)() {
return 0;
}
template class
部分保持不变,因此我不打算对其进行详细说明。让我们看看函数 foo
.
在第一个代码中,foo()
的return值是auto(*)() -> tmp<int>(*)()
,这是一个指向函数的指针return另一个指针,它指向一个函数 returning tmp<int>
.
因为您总是可以定义函数指针,例如:
base_type_t (*pointer_name)(parameter_list);
用一个函数(即func_name()
)递归pointer_name
可以声明一个函数,其return值是这样一个指针:
base_type_t (*func_name())(parameter_list);
~~~~~~~~~~~
所以现在(*func_name())(parameter_list)
可以起到另一个作用了。让我们把它放回到函数指针定义语法中:
base_type_t (*(*func_name())(parameter_list))(parameter_list);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
清除参数列表(它们是空的)并用正确的类型替换标识符给出:
base_type_t (*(*func_name())(parameter_list))(parameter_list);
tmp<int> (*(* foo ())( /* Empty */ ))( /* Empty */ );
// Turns to
tmp<int> (*(*foo())())();
正如其他人已经建议的那样,https://cdecl.org/ 是一个很好的代码分析器,尽管它可能会给您另一个不太容易理解的句子。
作为对@Vittorio 答案的补充,Clockwise Spiral Rule 可以帮助我们破译复杂类型:
从未知元素开始,向spiral/clockwise方向移动;遇到以下元素时用对应的英文语句替换:
[X]
或[]
Array
X
size of... or Array undefined size of...(type1, type2)
Function passing type1 and type2 returning...
*
pointer(s) to...
在 spiral/clockwise 方向继续这样做,直到所有标记都被覆盖。始终首先解决括号中的任何问题!
这里:
+-----------+
| +------+ |
| | >-v | |
temp<int> (*(*foo())())()
| | ^---+ | |
| ^--------+ |
+--------------+
foo
是一个函数,返回一个指向函数的指针,返回一个指向函数的指针,返回一个temp<int>
。
现在,@UKmonkey 刚刚将此规则重命名为 C++ Guru Snail 规则 或简称 CGSR:
/ /
L_L_
/ \
|00 | _______
|_/ | / ___ \
| | / / \ \
| |_____\ \_ / /
\ \____/ /_____
\ _______________/______\.............................