![]() |
善良的红茶 · SQLPrepare 函数 - ODBC ...· 1 月前 · |
![]() |
一身肌肉的莲藕 · VS2022创建CLR调用OpenCv ...· 1 月前 · |
![]() |
绅士的电脑桌 · useState使用ref从父函数组件传递时 ...· 1 月前 · |
![]() |
威武的马克杯 · react相关面试知识点总结 - ...· 1 月前 · |
![]() |
有胆有识的泡面 · 「react进阶」一文吃透react-hoo ...· 1 月前 · |
![]() |
有爱心的灌汤包 · 联想小新Pro ...· 3 月前 · |
![]() |
开朗的熊猫 · 杭州第19届亚运会开幕式_百度百科· 5 月前 · |
![]() |
鬼畜的充值卡 · 杭州私立小学排名学费 - 百度· 6 月前 · |
![]() |
考研的大脸猫 · 南京大屠杀和遍布东北的“万人坑”|日本关东军 ...· 11 月前 · |
![]() |
面冷心慈的保温杯 · 开局签到至尊丹田第99话 - 抖音· 1 年前 · |
请考虑以下示例:
struct S {
template<typename T = void>
friend void foo(S) {
int main() {
foo(s); // (1)
foo<void>(s); // (2)
}
我的GCC 9.2.0未能编译
(2)
,错误如下:
a.cpp: In function 'int main()':
a.cpp:10:5: error: 'foo' was not declared in this scope
10 | foo<void>(s);
| ^~~
a.cpp:10:9: error: expected primary-expression before 'void'
10 | foo<void>(s);
| ^~~~
然而,
(1)
工作得很好。为什么会这样呢?如何使用显式模板参数调用
foo
?
发布于 2020-03-07 18:44:28
类体中的
friend
函数定义不会使
friend
函数在封闭的名称空间范围内显示到通常的非限定名称查找(尽管它们被放置在这个命名空间范围中)。
为了使其可见,您需要在命名空间范围中为模板添加一个声明(这在定义之前还是之后并不重要):
struct S {
template<typename T = void>
friend void foo(S) {
template<typename T>
void foo(S);
int main() {
foo(s); // (1)
foo<void>(s); // (2)
}
现在的问题是为什么
foo(s)
工作。这是因为依赖于参数的查找。在没有嵌套名称说明符的函数调用中,还搜索调用参数类型(以及其他类型)的类和包围名称空间,以查找匹配的函数重载。对于依赖于参数的查找,只能在类体中声明的
friend
s是可见的。这样就找到了调用
foo(s)
的匹配函数。
foo<void>(s)
应该以同样的方式工作,因为名称是不合格的,而且
s
是
S
类型的,所以ADL应该再次在
S
中找到朋友
foo
。
然而,还有另一个问题要考虑。当编译器读取
foo
时,它必须决定
foo
是否可以是一个模板,因为它在
foo
之后改变了对
<
的解析。
要确定这一点,需要在
foo
上进行不限定名称查找。在C++20之前,只有在查找找到某种类型的模板时,
foo
才会被视为模板名。但是,在您的情况下,不限定名查找没有发现任何内容,因为唯一的
foo
对于普通的非限定名查找是不可见的。因此,
foo
将不被视为模板,
foo<void>
也不会被解析为模板id。
在C++20中,规则被更改,如果不限定名称查找找到一个普通函数,或者完全不使用该名称,那么
foo<void>
也将被视为一个模板id。在这种情况下,调用的下面的ADL将找到
foo
,并且调用将成功。
因此,代码将像在C++20和pre++20中一样工作,实际上,您只需要声明任何名为
foo
的模板就可以得到
foo<void>(s)
,以找到由ADL建立的好友
foo
。例如:
struct S {
template <typename T = void>
friend void foo(S) {}
template<int>
void foo();
int main() {
foo(s); // (1)
foo<void>(s); // (2)
}
发布于 2020-03-07 18:38:39
Clang 在哥德波特 能够提供一些启示:
<source>:9:5: warning: use of function template name with no prior declaration in function call with explicit template arguments is a C++20 extension [-Wc++20-extensions]
foo<void>(s);
1 warning generated.
在C++20到达并修复它之前,这种语法似乎并不是语言的一部分。
由于
foo()
是在
S
结构中完全实现的,因此在
main()
中没有可见的模板
foo
。因此,编译器不理解它需要做ADL,并且无法找到
foo()
。比如@0x499602D2。
一种解决方案是更新编译器,另一种解决方案是在
S
之外实现
S
,还可以添加一个前向声明来提供默认的模板参数:
struct S;
template<typename T = void>
void foo(S); // (a)
struct S {
template<typename T>
friend void foo(S); // (b)
template<typename T>
void foo(S) { // (c)
// Needs S to be complete.
![]() |
开朗的熊猫 · 杭州第19届亚运会开幕式_百度百科 5 月前 |
![]() |
鬼畜的充值卡 · 杭州私立小学排名学费 - 百度 6 月前 |
![]() |
考研的大脸猫 · 南京大屠杀和遍布东北的“万人坑”|日本关东军_网易订阅 11 月前 |
![]() |
面冷心慈的保温杯 · 开局签到至尊丹田第99话 - 抖音 1 年前 |