【问题标题】:g++ and clang++ different behaviour with friend template function defined inside a template classg++ 和 clang++ 与在模板类中定义的友元模板函数的不同行为
【发布时间】:2018-10-16 01:50:19
【问题描述】:

另一个类型的问题“谁在 g++ 和 clang++ 之间是对的?”供 C++ 标准专家使用。

以下代码

template <int>
struct foo
 {
   template <typename>
   friend void bar ()
    { }
 };

int main ()
 {    
   foo<0>  f0;
   foo<1>  f1;
 }

使用 clang++ 编译没有问题(只有两个“未使用的变量”警告)但给出以下错误

tmp_002-11,14,gcc,clang.cpp: In instantiation of ‘struct foo<1>’:
tmp_002-11,14,gcc,clang.cpp:27:12:   required from here
tmp_002-11,14,gcc,clang.cpp:20:16: error: redefinition of ‘template<class> void bar()’
    friend void bar ()
                ^~~
tmp_002-11,14,gcc,clang.cpp:20:16: note: ‘template<class> void bar()’ previously defined here

用 g++ 编译。

像往常一样,问题是:谁是对的? g++ 还是 clang++ ?

在我的 Debian 平台中使用 clang++ 3.9.1 和 g++ 6.3.0 检查。但是,在 Wandbox 中尝试,似乎与更新的版本相同。

【问题讨论】:

  • 您可以通过删除 template &lt;typename&gt; 来简化您的代码,并在使用 GCC 时得到相同的错误。
  • @NeilButterworth - 我知道:在这种情况下,两个编译器都有相同的错误。
  • 为了更有趣:godbolt.org/g/y7mtWX 不管标准怎么说,这肯定也是一个clang错误,改变f0和f1的顺序是没有意义的定义改变了结果,没有任何诊断。
  • 更有趣:如果您在全局命名空间中声明函数:template &lt;typename&gt; void bar(); 并只留下 一个 变量,然后调用 bar&lt;int&gt;(); 在 GCC 上编译并导致 ' Clang 上的未定义引用。
  • Related: “CWG 同意此类技术(通过在模板中定义友元函数的有状态模板元编程)应该是错误的,尽管禁止它们的机制尚未确定。” 我没找到,但也许有一些相关的缺陷报告?

标签: c++ templates language-lawyer friend


【解决方案1】:

GCC 在这种情况下是正确的。

相关标准措辞在[temp.inst]/2:

类模板特化的隐式实例化原因
— 声明的隐式实例化,但不是 定义,未删除的类成员函数,成员 类、作用域成员枚举、静态数据成员、成员 模板和朋友;和
[...]
但是,为了 确定实例化的重新声明是否有效 到 6.2 和 12.2,声明对应于 模板被认为是一个定义。 [ 例子: [...]

template<typename T> struct Friendly {
   template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)

——结束示例 ]

与朋友相关的部分由DR2174添加到本段并以C++17发布(这是一份缺陷报告,因此编译器也应将其应用于以前的标准版本)。


最近版本的 MSVC 和 EDG 在严格模式下也拒绝代码,抱怨重新定义。

[temp.inject]/1 有点相关,但只讲友函数,不讲友函数模板:

Friend 类或函数可以在类模板中声明。 当一个模板被实例化时,它的朋友的名字被处理 好像专业化已在其点明确声明 实例化。

【讨论】:

    猜你喜欢
    • 2014-06-20
    • 2016-10-19
    • 2016-06-23
    • 2018-01-06
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    相关资源
    最近更新 更多