类模板的朋友功能

Adr*_*thy 8 c++ friend function-templates non-member-functions

我有一个课程模板Foo<T>.

我想实现一个非成员函数Bar,它需要两个Foos并返回一个Foo.我想Bar成为一名非会员,因为写作者Bar(f1, f2)比写作更自然f1.Bar(f2).我也想Bar成为inline因为计算是微不足道的.

template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

诀窍是Bar需要访问Foo私人数据.我不希望拥有私有数据的访问者 - 没有充分的理由将私有数据暴露给用户.所以我想结交Bar一个朋友Foo.

template <typename T>
class Foo {
  ...
  private:
    T w, x, y, z;
    friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
Run Code Online (Sandbox Code Playgroud)

这是我遇到麻烦的地方.编译器抱怨:

当友元声明引用功能模板的特化时,不能使用内联说明符.

这个规则是由标准强加的还是特定于MSVC++?

这是我尝试过的:

  • 创建Bar一个const公共成员函数,然后声明一个简单返回的非成员版本lhs.Bar(rhs).这似乎是最不讨厌的解决方案.

  • 删除inline提示,知道编译器将决定内联而不管提示.这是否会违反单一定义规则?它仍然必须在头文件中定义,因为它是一个函数模板.

  • 使用虚拟模板类型声明成员函数:

    template <typename T>
    class Foo {
      ...
      private:
        T w, x, y, z;
    
        // Note that this declaration doesn't actually use Dummy.  It's just there to
        // satisfy the compiler.     
        template <typename Dummy>
        friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
    };
    
    Run Code Online (Sandbox Code Playgroud)

我不完全确定为什么会这样,但它确实满足了编译器.

有更好的解决方案吗?

Ste*_*sop 5

如果计算是微不足道的,我会写:

template <typename T>
class Foo {
  ...
  private:
    T w, x, y, z;
  public:
    friend Foo Bar(const Foo &lhs, const Foo &rhs) {
        ...
    }
};
Run Code Online (Sandbox Code Playgroud)

这不会违反ODR - 它是一个具有外部链接的内联函数(3.2/5从ODR中排除这一点,但定义相同,7.1.2/3表示它是内联的).

但是,这并没有定义函数模板Bar<T>,它只是定义了一组函数重载Bar.可能有一些原因,在问题中没有说明,这意味着这对你不起作用,因为你实际上需要模板.