联合中的友元函数出现错误“...没有命名类型”——为什么?怎么修?

Error "... does not name a type" in a friend function in a union - why? How to fix?

我有以下代码,它尝试为 union 定义和调用输出 operator:

#include <iostream>
#include <stdint.h>

template <typename T>
union test
{
    using mytype = T;
    friend std::ostream& operator<<(std::ostream& stream, test<T> t)
    {
        stream << static_cast<mytype>(65);
    }
};

int main() {
    test<int> t;
    std::cout << t;
    return 0;
}

编译失败,出现以下错误(实际上是两个错误):

prog.cpp: In function ‘std::ostream& operator<<(std::ostream&, test)’:
prog.cpp:10:28: error: ‘mytype’ does not name a type
      stream << static_cast<mytype>(65);
                            ^~~~~~
prog.cpp: In function ‘int main()’:
prog.cpp:15:10: error: non-template type ‘test’ used as a template
  test<int> t;
          ^

如果我将 union 替换为 struct,它会正常工作(打印 65)。

如果我将 friend 替换为成员函数,它也可以工作,但我必须使用此 friend 语法,因为我想输出 operator.

我还能做些什么来帮助编译器理解我的代码?

我使用的是 gcc 5.3.0;然后我在gcc 6.3 here的在线版本上试了一下,它显示了同样的问题。它从不在 MS Visual Studio 2017 上显示任何编译错误。

这是 GCC 错误。该函数是内联定义的,因此名称查找应遵循与成员函数相同的规则。

[basic.lookup.unqual]

9 Name lookup for a name used in the definition of a friend function ([class.friend]) defined inline in the class granting friendship shall proceed as described for lookup in member function definitions. If the friend function is not defined in the class granting friendship, name lookup in the friend function definition shall proceed as described for lookup in namespace member function definitions.

我用 GCC 8.2 测试 reproduced your error with your code. But it had no issues when the class-key was switched from union to struct, and it also had no problem 友元函数是否是成员。

值得注意的是 GCC bug 85576,它报告了您遇到的第二个错误,这无疑是相关的。

程序格式正确,因此这是一个 GCC 错误。

除了切换到符合标准的编译器之外,您还可以通过使用具有匿名联合成员的非联合 class 而不是普通联合来解决该错误:

template <typename T>
struct test {
    using mytype = T;
    friend std::ostream& operator<<(std::ostream& stream, test<T> t)
        {
            stream << static_cast<mytype>(65);
            return stream;
        }
    union {
        // the union members
    };
};