C++ 模板内部 Class 友元运算符重载

C++ Template Inner Class Friend Operator Overload

我正在尝试为 operator!= 实现重载,比较两个不同类型的对象(InnerAInnerB)。这两种类型都定义为模板 class (Outer) 中的嵌套 classes。重载需要成为两个 classes 的友元,因为它访问每个的私有字段。

template<typename Type> class Outer
{
public:
    class InnerA;
    class InnerB;
};


template<typename Type> bool operator!=(const typename Outer<Type>::InnerA& lhs, const typename Outer<Type>::InnerB& rhs);


template<typename Type> class Outer<Type>::InnerA
{
    const int val = 0;
    friend bool operator!=<>(const InnerA& lhs, const typename Outer<Type>::InnerB& rhs);
};


template<typename Type> class Outer<Type>::InnerB
{
    const int val = 1;
    friend bool operator!=<>(const typename Outer<Type>::InnerA& lhs, const InnerB& rhs);
};


template<typename Type> bool operator!=(const typename Outer<Type>::InnerA& lhs, const typename Outer<Type>::InnerB& rhs)
{
    return lhs.val != rhs.val;
}


int main()
{
    bool b = Outer<int>::InnerA() != Outer<int>::InnerB();
}

以上代码编译失败,发出:

 In instantiation of 'class Outer<int>::InnerA':
34:33: required from here 
15:17: error: template-id 'operator!=<>' for 'bool operator!=(const Outer<int>::InnerA&, const Outer<int>::InnerB&)' does not match any template declaration 
 In instantiation of 'class Outer<int>::InnerB': 
34:57: required from here 
22:17: error: template-id 'operator!=<>' for 'bool operator!=(const Outer<int>::InnerA&, const Outer<int>::InnerB&)' does not match any template declaration 
 In function 'int main()': 
34:35: error: no match for 'operator!=' (operand types are 'Outer<int>::InnerA' and 'Outer<int>::InnerB') 
34:35: note: candidate is: 
26:30: note: template<class Type> bool operator!=(const typename Outer<Type>::InnerA&, const typename Outer<Type>::InnerB&) 
26:30: note: template argument deduction/substitution failed: 
34:57: note: couldn't deduce template parameter 'Type'

虽然可能有更好的方法来实现类似的结果,但我很好奇我的代码到底出了什么问题。谢谢!

template<typename Type> class Outer<Type>::InnerA
{
   friend bool operator!=(const InnerA& lhs, const typename Outer<Type>::InnerB& rhs) { return true; }
};
template<typename Type> class Outer<Type>::InnerB
{
  friend bool operator!=(const typename Outer<Type>::InnerA& lhs, const InnerB& rhs) { return true; }
};

这些是非模板朋友。他们也有冲突。所以实现其中一个,省略另一个。

它们将通过 ADL 找到。

我找到了以下解决方法,将重载重构为嵌套 类 之一的方法:

template<typename Type> class Outer
{
public:
    class InnerA;
    class InnerB;
};


template<typename Type> class Outer<Type>::InnerA
{
    const int val = 0;
public:
    bool operator!=(const typename Outer<Type>::InnerB& other);
};


template<typename Type> class Outer<Type>::InnerB
{
    const int val = 1;
    friend bool Outer<Type>::InnerA::operator!=(const InnerB& other);
};


template<typename Type> bool Outer<Type>::InnerA::operator!=(const typename Outer<Type>::InnerB& other)
{
    return val != other.val;
}


int main()
{
    bool b = Outer<void>::InnerA() != Outer<void>::InnerB();
}

但是,我仍然很好奇是否可以像问题中那样使用非成员朋友功能来完成同样的事情。

问题中代码的问题最终是没有尝试对嵌套在依赖类型中的类型名称进行模板推导(例如 Outer<Type>::Inner)。

这个问题本质上是 Nested template and parameter deducing. A detailed explanation on why this is a problem can be found here 的重复。