【问题标题】:Templated Class Friend Operator Member Function模板类朋友运算符成员函数
【发布时间】:2016-08-27 14:08:51
【问题描述】:

我正在尝试在模板类中获取一个友元函数以进行编译,但错误消息和警告我不明白。我已经演示了这个问题。我得到的错误是:

prog.cpp:8:57: error: non-class, non-variable partial specialization C operator+(const B& lhs, const C& rhs);

prog.cpp:15:59: 警告:友元声明 'C operator+(const B&, const C&)' 声明了一个非模板函数 [-Wnon-template-friend] 朋友 C 运算符+(const B& lhs, const C& rhs);

prog.cpp:15:59: 注意:(如果这不是您想要的,请确保函数模板已经声明并在此处的函数名称后添加 )

#include <iostream>
using namespace std;

template<typename A, typename B>
class C;

template<typename A, typename B>
C<A, B> operator+<A, B>(const B& lhs, const C<A, B>& rhs);

template<typename A, typename B>
struct C
{
    A val_;
    C operator+(const C& other) const;
    friend C<A, B> operator+(const B& lhs, const C<A, B>& rhs);
};

template<typename A, typename B>
C<A, B> C<A, B>::operator+(const C<A, B>& other) const
{
    C<A, B> c;
    c.val_ = this->val_ + other.val_;
    return c;
}

template<typename A, typename B>
 C<A, B> operator+(const B& lhs, const C<A, B>& rhs)
{
    C<A, B> c;
    c.val_ = lhs + rhs.val_;
    return c;
}

int main() 
{
    C<string, char> c0,c1;
    c0.val_ = " C0 ";
    c1.val_ = " C1 ";
    cout << "Stuct:" << (c0 + c1).val_ << '\n';
    cout << "Friend:" << ('~' + c1).val_ << endl;
    return 0;
}

【问题讨论】:

  • 你不需要operator+的第一个声明,这是错误的。
  • 这是问题的一个例子。我的实际代码中需要三种形式:C 运算符+(const C& other)、C 运算符+(const B& other)和 C 运算符(const B& lhs、const C& rhs)。注:不是实际的编译代码,只是需要的一般形式。

标签: c++ templates c++11 friend


【解决方案1】:

最简单的就是在类中内联代码:

template <typename A, typename B>
struct C
{
    A val_;
    C operator+(const C& other) const
    {
        C c;
        c.val_ = this->val_ + other.val_;
        return c;
    }

    friend C operator+ (const B& lhs, const C& rhs)
    {
        C c;
        c.val_ = lhs + rhs.val_;
        return c;
    }
};

Demo

类中没有内联的代码,需要注意声明的前向声明顺序,奇怪语法&lt;&gt;:

template <typename A, typename B> struct C;

template <typename A, typename B>
C<A, B> operator+ (const B& lhs, const C<A, B>& rhs);

template <typename A, typename B>
struct C
{
    A val_;

    friend C<A, B> operator+<> (const B& lhs, const C<A, B>& rhs);

    C operator+(const C& other) const;
};


template <typename A, typename B>
C<A, B> operator+ (const B& lhs, const C<A, B>& rhs)
{
    C<A, B> c;
    c.val_ = lhs + rhs.val_;
    return c;
}

template <typename A, typename B>
C<A, B> C::operator+(const C<A, B>& other) const
{
    C<A, B> c;
    c.val_ = this->val_ + other.val_;
    return c;
}

Demo

【讨论】:

    【解决方案2】:

    此声明:

    template<typename A, typename B>
    C<A, B> operator+<A, B>(const B& lhs, const C<A, B>& rhs);
    

    ...因为operator+( 之间的&lt;A,B&gt; 是错误的,我真的不知道你想在这里做什么。如果您要专门化一个模板化的operator+,您会使用此表单,但您不在这里,您是重载一个。

    这个声明应该是:

    template<typename A, typename B>
    C<A, B> operator+ (const B& lhs, const C<A, B>& rhs);
    

    那么你应该在你的friend声明中明确指定你想要一个专门的版本:

    friend C<A,B> operator+<>(const B& lhs, const C<A,B>& rhs);
    

    你需要把它放在你的operator+之前,否则编译器会认为这是一个非模板函数的特化。

    无论如何,如果您没有真正的理由将代码放在 C 类之外,我会选择 @Jarod42 解决方案。


    您的整个代码应如下所示:

    // Declaration of struct C with delayed definition
    template <typename A, typename B>
    struct C;
    
    // Initial declaration of templated operator+
    template <typename A, typename B>
    C<A, B> operator+ (const B&, const C<A, B>&);
    
    // Definition of C
    template <typename A, typename B>
    struct C {
    
        friend C operator+<> (const B&, const C&);
    
        // This must be AFTER the templated operator+
        C operator+ (const C&) const;
    };
    
    template<typename A, typename B>
    C<A, B> C<A, B>::operator+(const C<A, B>& other) const {
    
    }
    
    template<typename A, typename B>
    C<A, B> operator+(const B& lhs, const C<A, B>& rhs) {
    
    }
    

    【讨论】: