【问题标题】:An explicit specialization cannot be a friend declaration显式特化不能是友元声明
【发布时间】:2015-01-04 15:35:35
【问题描述】:

代码

template <typename T>
void foo(const T& t)
{}

template <typename T>
class A
{
    template <>
    friend void foo<T>(const T& t)
    {}
};

给出编译错误

"defining explicit specialization ‘foo<T>’ in friend declaration friend void foo<T>(const T& t)"

当使用 gcc 和

编译时
"error C3637: 'A<int>::foo' : a friend function definition cannot be a specialization of a unction template"

在 VS2013 中编译时

我知道标准是这样说的,但是为什么呢?我想了解原因(幕后) 有很多文章写着“显式专业化不能是朋友声明。”,但我不明白为什么。有什么想法吗?

【问题讨论】:

  • gcc 报告给定代码的 explicit specialization in non-namespace scope 'struct A&lt;T&gt;'template-id 'foo&lt;T&gt;' in declaration of primary template
  • 对不起,我从其他来源复制粘贴
  • 显式特化防止隐式实例化。每次为一组新的模板参数实例化 A 时,您都会添加另一个显式的 foo 特化。如果 foo 已经为相同的模板参数 [temp.expl.spec]/6 隐式实例化,则添加该特化是不正确的,不需要诊断。
  • @dyp 如果我清楚地理解您的评论,那么对于类模板中的每个函数模板专业化都是如此,而不仅仅是朋友?但编译错误与友元函数特化有关。除了在评论中提到的之外,我认为对朋友来说还有一些特别的东西
  • 这适用于任何类型的模板(在显式特化之前使用相同的模板参数进行隐式实例化是格式错误的,NDR)。但是,您显示的代码将添加新的显式特化的方式很可能会发生此类违规行为,因为 a)新的特化将被隐式添加,并且 b)在主模板之外的另一个范围内。

标签: c++ templates friend-function explicit-specialization


【解决方案1】:

第一次(也可能是唯一一次)在类模板中声明显式特化意味着显式特化仅在模板被实例化后才“存在” - 无论声明是否依赖于模板参数或不是。 这会产生许多问题,并会在各种情况下导致违反 ODR,其中许多可能是格式错误的 NDR;主要是因为cmets中@dyp提到的那段,[temp.expl.spec]/6

此外,没有外部声明的类中的友元函数定义使得该函数只能通过 ADL 调用。显然,如果显式特化仅在调用具有关联的参数类型时适用,那将是绝对荒谬的——同样,更不用说违反 ODR。

这些和其他原因使得这样的构造过于复杂,但也不是很有用:您可以简单地做的就是将专业化添加为friend,而不以任何方式表明该专业化是实例化的还是显式的专业的。

friend void foo<T>(const T&);

然后可以在命名空间范围内添加任何显式特化。

【讨论】:

  • 或者你可以重载,通过在里面定义一个非模板友元函数。
  • 为了完整起见,类中的友元函数定义通常允许在没有 ADL 的情况下调用该函数,只是不使用类内声明。只要有类外声明可用,就可以了,所以:struct S { friend void f() { } } void f(); int main() { f(); } 完全有效。但是,显式模板特化需要在使用时声明这些显式特化,因此类内声明还不够好。
  • @Columbo 感谢您的回答,但您能否更清楚地解释 ADL 案例,我不明白这个问题。如果在类中定义了函数模板特化,那么它应该采用类的参数或从该类派生的类,因为 ADL 机制应该起作用。那么带有此类(类或派生)参数的模板专业化定义有什么问题?
猜你喜欢
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 2012-09-19
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多