C++ 类模板的友元函数

C++ 类模板的友元函数,c++,friend,function-templates,non-member-functions,C++,Friend,Function Templates,Non Member Functions,我有一个类模板Foo template <typename T> class Foo { ... private: T w, x, y, z; friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs); }; 我想实现一个非成员函数Bar,它接受两个Foos并返回一个Foo。我希望Bar成为非成员,因为调用方编写Bar(f1,f2)比f1.Bar(f2)

我有一个类模板
Foo

template <typename T>
class Foo {
  ...
  private:
    T w, x, y, z;
    friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
我想实现一个非成员函数
Bar
,它接受两个
Foo
s并返回一个
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) {
  ...
}
这就是我遇到麻烦的地方。编译器抱怨:

当友元声明引用函数模板的专门化时,不能使用内联说明符

这条规则是由标准规定的还是特定于MSVC++

以下是我尝试过的:

  • 使
    Bar
    成为常量公共成员函数,然后声明一个非成员版本,该版本只返回
    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);
    };
    
    模板
    福班{
    ...
    私人:
    tw,x,y,z;
    //注意,这个声明实际上并没有使用Dummy,它只是用来
    //满足编译器的要求。
    模板
    friend Foo Bar(常富&左、常富&右);
    };
    
我不完全确定为什么会这样,但它确实满足了编译器的要求


有更好的解决方案吗?

如果计算很简单,我会写:

template <typename T>
class Foo {
  ...
  private:
    T w, x, y, z;
  public:
    friend Foo Bar(const Foo &lhs, const Foo &rhs) {
        ...
    }
};
模板
福班{
...
私人:
tw,x,y,z;
公众:
friend Foo Bar(恒富&左、恒富&右){
...
}
};
这与ODR没有冲突——它是一个带有外部链接的内联函数(3.2/5将其从ODR中排除,但定义相同,7.1.2/3称其为内联函数)


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

我最喜欢选项1:

template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
    return lhs.Bar(rhs);
}

template <typename T>
class Foo {
  ...
    Foo<T> Bar(const Foo<T> &other) const;
  private:
    T w, x, y, z;
};
模板
内联Foo栏(常量Foo和lhs、常量Foo和rhs){
返回左侧酒吧(右侧);
}
模板
福班{
...
富吧(常富及其他)常富;
私人:
tw,x,y,z;
};

然后,该功能安全地包含在类中,但为了方便起见,您提供了一个包装函数。

Bar是一个模板,因此它也必须是友元声明中的模板

您不必使用伪参数,但可以使用

 template <typename U>
 friend Foo<U> Bar(const Foo<U> &lhs, const Foo<U> &rhs);
模板
friend Foo Bar(常富&左、常富&右);

这里不能使用T作为模板参数,因为作用域中已经有一个外部T。

我试过了,但Foo为Bar声明一个friend函数似乎不对,其中U与T的类型不同。这可能没有什么实际的危害,但感觉不对。这就是为什么我最终使用了伪参数。它可能看起来是错误的,但目前(C++03)您无法为特定的T选择您的朋友。您的伪参数也可以是与T.+1不同的任何类型。就我的具体情况而言,我越来越喜欢这个。我仍然对一般情况感到好奇。我没有想到这一点,它很好地解决了问题,满足了所有的约束条件。