【问题标题】:C++ Template Inner Class Friend Operator OverloadC++ 模板内部类友元运算符重载
【发布时间】:2018-05-17 01:30:52
【问题描述】:

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

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'

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

【问题讨论】:

    标签: c++ templates friend


    【解决方案1】:
    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 找到。

    【讨论】:

    • 我认为这个解决方案不适合我的目的。 operator!= 重载需要同时成为 InnerAInnerB 的朋友才能访问各自的私有字段。我会更新我的问题以明确这一点。
    • @alex 当然,这是问题的附加内容。为了解决这个问题,转发给另一个非运营商。运算符的一个重要部分是推断调用哪一个;非模板朋友很容易通过 ADL 找到。同时,非推导上下文模板只能通过显式传递类型来调用,这不是您想要的运算符。
    • 我想这归结为我对 ADL 缺乏足够的了解。感谢您的帮助。
    【解决方案2】:

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

    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&lt;Type&gt;::InnerAType 不能推断。你可以使用Outer&lt;int&gt;::InnerA().operator !=&lt;int&gt;(Outer&lt;int&gt;::InnerB())。非模板友元函数是解决方案(对于 ADL 并且使推导不成问题)。
    • @Jarod42 我第一次读的时候没看懂你的回复,但我刚刚找到了一篇论文,证实了你的说法并解释了原因。我会做出一个新的答案来反映这一点。谢谢!
    【解决方案3】:

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

    这个问题本质上是Nested template and parameter deducing 的重复。可以在here 找到有关此问题的详细解释。

    【讨论】:

      猜你喜欢
      • 2011-04-28
      • 2011-05-08
      • 2021-05-18
      • 2011-06-07
      • 2010-11-20
      • 1970-01-01
      相关资源
      最近更新 更多