为什么不能使用显式模板参数调用模板朋友功能?

叶普顿

考虑以下示例:

struct S {
    template<typename T = void>
    friend void foo(S) {
    }
};

int main() {
    S s;
    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使用显式模板参数调用?

核桃

friend类主体中的函数定义不会使friend函数在封闭的名称空间范围中可见(对于通常的非限定名称查找)(尽管它们已放置在此名称空间范围中)。

为了使其可见,您需要在名称空间范围内为模板添加一个声明(这是在定义之前还是之后都没有关系):

struct S {
    template<typename T = void>
    friend void foo(S) {
    }
};

template<typename T>
void foo(S);

int main() {
    S s;
    foo(s); // (1)
    foo<void>(s); // (2)
}

现在的问题是为什么foo(s)有效。这是因为依赖于参数的查找。在没有嵌套名称说明符的函数调用中,还将搜索调用参数(和其他参数)类型的类和封闭的名称空间,以查找匹配的函数重载。对于依赖于参数的查找,friend仅在类主体中声明的s是可见的。通过这种方式,foo(s)可以找到呼叫的匹配功能

foo<void>(s)应工作方式相同,因为这个名字是不合格的,并s是类型的S,所以ADL应该再次找到朋友foo里面S

但是,还有另一个问题要考虑。编译器读取时foo,必须决定是否foo可以是模板,因为它更改了<following的解析foo

为了确定这一点,对进行了不合格的名称查找foo在C ++ 20之前,foo仅当此查找通过该名称找到某种模板时,才被视为模板名称。但是在您的情况下,不合格的名称查找无法找到任何内容,因为foo对于普通的不合格的名称查找来说,唯一的内容是不可见的。因此,foo将不会被视为模板,foo<void>也不会被解析为模板ID。

在C ++ 20中,更改了规则,并且如果不合格的名称查找通过该名称找到一个普通函数,或者根本找不到任何东西,则foo<void>也将被视为模板ID。在这种情况下,将找到foo该呼叫的以下ADL,并且该呼叫将成功。

因此,代码会工作在C ++ 20和PRE-C ++ 20,你实际上只需要声明任何由名模板foo拿到foo<void>(s)找到friendedfoo通过ADL。例如:

struct S {
  template <typename T = void>
  friend void foo(S) {}
};

template<int>
void foo();

int main() {
  S s;
  foo(s);        // (1)
  foo<void>(s);  // (2)
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么不能使用显式泛型参数调用泛型扩展方法?

为什么我不能通过模板参数声明一种朋友功能,但是可以使用别名

为什么不能使用模板模板参数将std :: vector <MyType>传递给此函数?

为什么clang拒绝可变参数模板的朋友功能

为什么在调用R的split函数时不能使用显式形式而不是magrittr管道?

为什么我允许显式实例化模板特化,而默认参数不能隐式转换为其他类型?

在C ++中,为什么不能使用另一个类的模板类型来与模板类成员函数成为朋友?

为什么不能隐式转换模板类型参数?

在 C++ 函数模板中,为什么我不能使用 lambda 来指定参数的数组大小?

为什么C ++显式实例化的模板方法不能覆盖虚拟方法?

为什么我不能使用显式类型来传递函数

模板模板参数的显式匹配

C ++:显式调用模板参数的typedef的析构函数

模板类的模板朋友功能,引入了新的模板参数

为什么在使用模板时不能使用前向声明?

c ++:为什么不能使用模板来推断容器和元素类型?

为什么我不能使用msvc在模板类中声明静态constexpr变量?

为什么通用函数模板不能使用fnx来确保它们是尾递归的?

为什么初始化std :: vector时不能使用模板整数?

为什么不能在模板化类中内联定义未模板化的朋友?

不能使用指针作为默认模板参数

为什么仅对功能模板使用模板参数推导/替换失败?

为什么函数模板不允许使用私有类型的显式特化?

为什么没有比较显式的函数名就不能将函数指针与模板函数进行比较?

模板参数类型“void”与显式使用“void”

是否可以调用显式指定模板参数的模板化强制转换运算符?

模板类的模板朋友功能

模板类的模板朋友功能

模板功能使用参数包时如何传递其他模板参数?