【问题标题】:Non-member operator overloading of inner class templates内部类模板的非成员运算符重载
【发布时间】:2014-04-07 18:01:50
【问题描述】:

我更喜欢在单独的文件中编写类和函数模板的定义,该文件自动包含在“public”标题之后。但是,我遇到了一个有趣的案例,我似乎无法做到这一点。

template <typename T>
class Outer
{
public:
    template <typename U>
    class Inner
    {
        friend bool operator ==(const Inner& lhs, const Inner& rhs);
    };
};

using Type = Outer<int>::Inner<short>;

int main()
{
    Type a;
    Type b;
    a == b;
}

是否可以单独编写适用于任何T 和U 的operator== 的定义?

【问题讨论】:

    标签: c++ templates c++11 operator-overloading


    【解决方案1】:

    对于特定的专业,是的:

    template <typename T>
    class Outer
    {
    public:
        template <typename U>
        class Inner
        {
            int x = 42;
            friend bool operator ==(const Inner& lhs, const Inner& rhs);
        };
    };
    
    using Type = Outer<int>::Inner<short>;
    
    bool operator ==(const Type& lhs, const Type& rhs) {
        return lhs.x == rhs.x;
    }
    
    int main()
    {
        Type a;
        Type b;
        a == b;
    }
    

    在您的示例中,模板的每个特化都与一个非模板函数成为朋友,该函数将该特定特化作为参数。你可以在类内定义这个函数(然后每次实例化模板时它都会被删除),或者你可以在类外定义它——但是你必须为你曾经使用的每个专业定义一个。

    【讨论】:

    • 在限定类定义主体的大括号内的类内含义。我想如果你足够绝望的话,原则上你可以将它移动到一个单独的文件中并在类定义中#include它。
    【解决方案2】:

    正如 Igor Tandetnik 指出的那样,您的示例声明了一个非模板友元函数,您必须为每个模板实例化重载该函数,这是允许内联定义友元函数的原因之一(因此它们可以通过模板本身不必是模板)。

    如果你想将朋友函数定义为模板,这是我能想到的最接近的:

    template <typename T>
    struct Outer {
        template <typename U>
        struct Inner;
    };
    
    template<typename T, typename U>
    bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & );
    
    template <typename T>
    template <typename U>
    struct Outer<T>::Inner {
        friend bool operator==<T,U>(Inner const &, Inner const &);
    };
    
    template<typename T, typename U>
    bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & ) {
        return true;
    }
    
    // I switched this out, because my gcc-4.6 doesn't
    // understand "using" aliases like this yet:
    typedef Outer<int>::Inner<short> Type;
    
    int main() {
        Type a;
        Type b;
        operator==<int,short>( a, b );
    }
    

    不幸的是,你会注意到这个算子函数的调用位置很尴尬:operator==&lt;int,short&gt;( a, b )。我相信像这样在嵌套类模板上定义函数模板会禁用(或至少干扰)参数推导,因此您必须显式指定模板参数(这意味着将其作为函数而不是运算符形式调用)。这就是内联朋友定义如此方便的原因。如果您真的想单独定义 operator== 的代码,我建议您定义 friend 内联来调用另一个函数模板(使用正确的模板参数),然后您可以将其定义为免费功能。

    【讨论】:

    • 啊,这是一个很好的解释,我现在将决定使用内联定义,但会记住您的建议。
    猜你喜欢
    • 2017-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多