超载+ C++ 中泛型类的运算符

发布于 2024-09-29 11:57:58 字数 1574 浏览 8 评论 0原文

我试图在森林类中重载 + 运算符,森林是树木的集合,而 + 运算符应该将两个森林合并为一个。我有以下代码作为我的类定义:

template<typename NODETYPE>
class Forest
{


    public:

        friend Forest& operator+<>(Forest&, Forest&);
        friend ostream& operator<<<>(ostream&, const Forest&);
        friend istream& operator>><>(istream&, Forest&);
        Forest();
        Forest( const Forest& otherForest);
        ~Forest();
        void nodes(int&) const;

    private:
        ForestNode<NODETYPE> *root;

        ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};

以下是我的operator+ 实现:

template<typename NODETYPE>
Forest& operator+<>(Forest& f1, Forest& f2)
{
    f3 = new Forest();
    f3.root = *f1.*root;
    f3.root.sibling = *f2.*root;
    *f1.root = 0;
    *f2.root = 0;
    return f3;
}

编译时出现以下错误:

|28|错误:预期的构造函数、析构函数或“&”之前的类型转换代币|

第28行指的是我的operator+实现的签名。

我认为要纠正它,我应该添加到返回类型,给出:

template<typename NODETYPE>
Forest<NODETYPE>& operator+<>(Forest& f1, Forest& f2)
{
    f3 = new Forest();
    f3.root = *f1.*root;
    f3.root.sibling = *f2.*root;
    *f1.root = 0;
    *f2.root = 0;
    return f3;
}

但这给了我以下错误:

|28|错误:'operator+'声明为非函数| |28|错误:“&”之前缺少模板参数代币| |28|错误:“f1”未在此范围内声明| |28|错误:“&”之前缺少模板参数代币| |28|错误:“f2”未在此范围内声明|

谁能帮我解决这个问题吗?我将非常非常感激。

I'm trying to overload the + operator in a forest class, a forest being a collection of trees, and the + operator is supposed to combine two forests into one. I have the following code as my class definition:

template<typename NODETYPE>
class Forest
{


    public:

        friend Forest& operator+<>(Forest&, Forest&);
        friend ostream& operator<<<>(ostream&, const Forest&);
        friend istream& operator>><>(istream&, Forest&);
        Forest();
        Forest( const Forest& otherForest);
        ~Forest();
        void nodes(int&) const;

    private:
        ForestNode<NODETYPE> *root;

        ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};

The following is my implementation of operator+:

template<typename NODETYPE>
Forest& operator+<>(Forest& f1, Forest& f2)
{
    f3 = new Forest();
    f3.root = *f1.*root;
    f3.root.sibling = *f2.*root;
    *f1.root = 0;
    *f2.root = 0;
    return f3;
}

I get the following error on compile:

|28|error: expected constructor, destructor, or type conversion before '&' token|

line 28 refers to the signature of my operator+ implementation.

I think to correct it i am supposed to add to the return type, giving:

template<typename NODETYPE>
Forest<NODETYPE>& operator+<>(Forest& f1, Forest& f2)
{
    f3 = new Forest();
    f3.root = *f1.*root;
    f3.root.sibling = *f2.*root;
    *f1.root = 0;
    *f2.root = 0;
    return f3;
}

But that gives me the following errors:

|28|error: declaration of 'operator+' as non-function| |28|error: missing template arguments before '&' token| |28|error: 'f1' was not declared in this scope| |28|error: missing template arguments before '&' token| |28|error: 'f2' was not declared in this scope|

Can anyone help me with this? I'd be very very thankful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蓝天 2024-10-06 11:57:58

编写operator+的关键是不要写operator+。相反,编写一个复制构造函数和operator+=:

template<class NodeType>
struct Forest {
  //...
  Forest(Forest const &other);
  //...
  Forest& operator+=(Forest const &other) {
    // code here
    return *this;
  }
  //...
};

现在我们添加operator+:

template<class NodeType>
struct Forest {
  //...
  friend Forest operator+(Forest a, Forest const &b) {
    a += b;
    return a;
  }
  //...
};

就是这样!复制通常是直接的(有时是不允许的),并且用 += 来思考可能比用 + 更简单(你有两个对象并改变其中一个,而不是从两个对象中创建第三个对象)。 op+ 的这种模式适用于任何类似的类型,甚至适用于类似的运算符,例如 -、* 和 /。

The key to writing operator+ is don't write operator+. Instead, write a copy ctor and operator+=:

template<class NodeType>
struct Forest {
  //...
  Forest(Forest const &other);
  //...
  Forest& operator+=(Forest const &other) {
    // code here
    return *this;
  }
  //...
};

Now we add operator+:

template<class NodeType>
struct Forest {
  //...
  friend Forest operator+(Forest a, Forest const &b) {
    a += b;
    return a;
  }
  //...
};

And that's it! Copying is usually straight-forward (sometimes by being disallowed) and it may be simpler to think in terms of += than + (you have two objects and mutate one, rather than create a third object out of two). This pattern for op+ works with any similar type, and even for similar operators such as -, *, and /.

智商已欠费 2024-10-06 11:57:58

运算符重载可能是好事,也可能是坏事。当它导致代码看起来更简单时,这很好。当它导致编写者重载不正确的语义(但仍是可编译的解决方案)或使用运算符的直观方式导致代码效率极低时,那就不好了。

请注意,后一个语句也适用于 std::string,这可能会产生大量副本,这就是为什么 C++03 标准规定字符串不必在内部存储在连续的缓冲区中(在过去,他们使用写时复制引用,并且可以存储对连接的两个字符串的此类引用,直到需要为止,随后发现它是非线程安全的,因此比简单地复制缓冲区成本更高,所以现在他们复制每个字符串。时间又效率低下)。

(请注意,识别线程和原子问题的 C++11 标准确保底层确实需要连续且以 null 终止,以使读取操作安全)。

operator+ 的正确签名(在所有类型都相同的情况下)如下:

T operator+( const T&, const T& );

作为成员函数,它是:

class T
{
    // make public if necessary
    T operator+( const T& rhs ) const;
};

每当operator += 可用时,您可以自动将operator+ 实现为模板

template<typename T, typename R>
T operator+( const T& lhs, const R& rhs )
{
    T copy(lhs);
    return copy += rhs;
}

如果您想声明一个重载运算符作为朋友,您的模板,这是正确的方法。我将用运算符<<来显示它

// first some forward declarations, assume ostream already declared with #include <iosfwd> minimum
template< typename T > class Forest;
template< typename T > std::ostream & operator<<( std::ostream & os, const Forest<T> & for );

template< typename T> class Forest
{
     friend std::ostream& operator<< <>( std::ostream&, const Forest<T> & );
     //rest of class Forest
};

template< typename T >
std::ostream & operator<<( std::ostream& os, const Forest<T> & forest )
{
    // implement
    return os;
}

您可以将类似的技术应用于您希望声明为类的友元的任何其他外部函数,即,

  1. 将您的类向前声明为模板,
  2. 将方法前向声明为模板函数,
  3. 使用 <> 使该函数成为友元。在表示参数的左括号之前
  4. 在类之后实现该函数。

Operator overloading can be a good or a bad thing. Good when it leads to simpler looking code. Bad when it leads to writers either overloading with incorrect semantics (yet a solution that compiles) or where the intuitive way to use the operator leads to highly inefficient code.

Note the latter statement can apply to std::string too, which could potentially make large numbers of copies, and which is why the C++03 standard states that a string does not have to be stored internally in a contiguous buffer (in the old days they used copy-on-write references to and could store such references to both strings being concatenated until required. Subsequently it was found to be non-threadsafe and making it so was more costly than simply copying the buffer so now they copy every time and are inefficient again).

(Note that the C++11 standard which recognises threading and atomic issues ensures that the underlying does need to be contiguous and null-terminated to make read operations safe).

The correct signature of operator+ (in the case all are the same type) is as follows:

T operator+( const T&, const T& );

As a member function it would be:

class T
{
    // make public if necessary
    T operator+( const T& rhs ) const;
};

You can implement operator+ automatically as a template whenever operator += is available with

template<typename T, typename R>
T operator+( const T& lhs, const R& rhs )
{
    T copy(lhs);
    return copy += rhs;
}

If you want to declare an overloaded operator of your template as a friend, this is the correct way to do it. I will show it with operator<<

// first some forward declarations, assume ostream already declared with #include <iosfwd> minimum
template< typename T > class Forest;
template< typename T > std::ostream & operator<<( std::ostream & os, const Forest<T> & for );

template< typename T> class Forest
{
     friend std::ostream& operator<< <>( std::ostream&, const Forest<T> & );
     //rest of class Forest
};

template< typename T >
std::ostream & operator<<( std::ostream& os, const Forest<T> & forest )
{
    // implement
    return os;
}

You would apply a similar technique to any other external function you wish to declare as a friend to your class, i.e.

  1. Forwardly declare your class as a template
  2. Forwardly declare the method as a template function
  3. Make the function a friend using <> before the opening parentheses denoting the parameters
  4. Implement the function after your class.
情绪 2024-10-06 11:57:58

您必须为所有 Forest 参数提供模板参数。

template<typename NODETYPE>
Forest<NODETYPE> operator+(Forest<NODETYPE>& f1, Forest<NODETYPE>& f2)

另外,请考虑将参数设为 const 引用,以确保您不要操纵它们。

几个stackoverflow 上有关友元函数模板的问题C++ FAQ 上也有一个页面,其中包含解释了一些基础知识。

You have to provide a template arguments for all Forest parameters.

template<typename NODETYPE>
Forest<NODETYPE> operator+(Forest<NODETYPE>& f1, Forest<NODETYPE>& f2)

Also, consider making the arguments const references to make sure you do not manipulate them.

There are several questions on stackoverflow regarding friend function templates. The C++ FAQ also has a page on them that explains some basics.

梨涡 2024-10-06 11:57:58

您可以按如下方式定义 operator+ 模板:

template< class NodeType >
Forest<NodeType> operator+( Forest<NodeType> const& f1, Forest<NodeType> const& f2)
{
    // Implementation.
}

Cheers &呵呵,,

You can define an operator+ template as follows:

template< class NodeType >
Forest<NodeType> operator+( Forest<NodeType> const& f1, Forest<NodeType> const& f2)
{
    // Implementation.
}

Cheers & hth.,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文