类模板上的运算符重载

发布于 2024-09-29 11:30:42 字数 1237 浏览 5 评论 0原文

我在为模板类定义一些运算符重载时遇到一些问题。让我们以这个假设的类为例。

template <class T>
class MyClass {
  // ...
};

operator+=

// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
    // ...
    return *this;
}

导致此编译器错误:

no match for 'operator+=' in 'classObj2 += classObj1'

operator<<

// In MyClass.h
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) {
    // ...
    return out;
}

导致此编译器警告:

friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function

我在这里做错了什么?

I'm having some problems defining some operator overloads for template classes. Let's take this hypothetical class for example.

template <class T>
class MyClass {
  // ...
};

operator+=

// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
    // ...
    return *this;
}

Results in this compiler error:

no match for 'operator+=' in 'classObj2 += classObj1'

operator<<

// In MyClass.h
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) {
    // ...
    return out;
}

Results in this compiler warning:

friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function

What am I doing wrong here?

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

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

发布评论

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

评论(5

彻夜缠绵 2024-10-06 11:30:42

您需要说出以下内容(因为您与整个模板成为朋友,而不仅仅是它的专门化,在这种情况下,您只需要在后面添加一个<> operator<<):

template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

实际上,除非它访问私有或受保护的成员,否则不需要将其声明为友元。由于您刚刚收到警告,看来您的友谊宣言并不是一个好主意。如果您只想将其声明为友元,可以像下面所示的那样,在类之前声明模板的单一特化,以便operator<< 被识别为模板。

// before class definition ...
template <class T>
class MyClass;

// note that this "T" is unrelated to the T of MyClass !
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// in class definition ...
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj);

上述和这种方式都将其特化声明为友元,但第一种将所有特化声明为友元,而第二种仅将operator<<的特化声明为朋友,其 T 等于授予友谊的类的 T

在另一种情况下,您的声明看起来不错,但请注意,您不能将 +=MyClass 转换为 MyClassTU 与该声明的类型不同时(除非您在这些类型之间有隐式转换)。您可以将您的 += 设为会员模板

// In MyClass.h
template<typename U>
MyClass<T>& operator+=(const MyClass<U>& classObj);


// In MyClass.cpp
template <class T> template<typename U>
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) {
  // ...
  return *this;
}

You need to say the following (since you befriend a whole template instead of just a specialization of it, in which case you would just need to add a <> after the operator<<):

template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

Actually, there is no need to declare it as a friend unless it accesses private or protected members. Since you just get a warning, it appears your declaration of friendship is not a good idea. If you just want to declare a single specialization of it as a friend, you can do that like shown below, with a forward declaration of the template before your class, so that operator<< is regognized as a template.

// before class definition ...
template <class T>
class MyClass;

// note that this "T" is unrelated to the T of MyClass !
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// in class definition ...
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj);

Both the above and this way declare specializations of it as friends, but the first declares all specializations as friends, while the second only declares the specialization of operator<< as a friend whose T is equal to the T of the class granting friendship.

And in the other case, your declaration looks OK, but note that you cannot += a MyClass<T> to a MyClass<U> when T and U are different type with that declaration (unless you have an implicit conversion between those types). You can make your += a member template

// In MyClass.h
template<typename U>
MyClass<T>& operator+=(const MyClass<U>& classObj);


// In MyClass.cpp
template <class T> template<typename U>
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) {
  // ...
  return *this;
}
南渊 2024-10-06 11:30:42
// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);


// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
  // ...
  return *this;
}

这对于模板无效。运算符的完整源代码必须位于使用它的所有翻译单元中。这通常意味着代码内联在标头中。

编辑:从技术上讲,根据标准,可以导出模板,但很少有编译器支持它。此外,如果模板在 MyClass.cpp 中为所有 T 类型显式实例化,您也可以执行上述操作,但实际上,这通常违背了模板的要点。

更多编辑:我通读了你的代码,它需要一些工作,例如重载运算符[]。此外,通常,我会将维度作为模板参数的一部分,允许在编译时捕获 + 或 += 的失败,并允许对类型进行有意义的堆栈分配。您的异常类还需要从 std::exception 派生。然而,这些都不涉及编译时错误,它们只是不是很好的代码。

// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);


// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
  // ...
  return *this;
}

This is invalid for templates. The full source code of the operator must be in all translation units that it is used in. This typically means that the code is inline in the header.

Edit: Technically, according to the Standard, it is possible to export templates, however very few compilers support it. In addition, you CAN also do the above if the template is explicitly instantiated in MyClass.cpp for all types that are T- but in reality, that normally defies the point of a template.

More edit: I read through your code, and it needs some work, for example overloading operator[]. In addition, typically, I would make the dimensions part of the template parameters, allowing for the failure of + or += to be caught at compile-time, and allowing the type to be meaningfully stack allocated. Your exception class also needs to derive from std::exception. However, none of those involve compile-time errors, they're just not great code.

睡美人的小仙女 2024-10-06 11:30:42

这帮助我解决了完全相同的问题。

解决方案:

  1. class本身的定义之前转发声明friend函数。例如:

     模板<类型名称 T>类我的类; // 预先声明模板类本身
       模板<类型名称 T> std::ostream&运算符<< (std::ostream&o, const MyClass &x);
    
  2. 在类中使用“<>”声明您的友元函数附加到函数名称后。

     朋友 std::ostream&运算符<< <> (std::ostream&o, const Foo&x);
    

This helped me with the exact same problem.

Solution:

  1. Forward declare the friend function before the definition of the class itself. For example:

       template<typename T> class MyClass;  // pre-declare the template class itself
       template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x);
    
  2. Declare your friend function in your class with "<>" appended to the function name.

       friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
    
薄暮涼年 2024-10-06 11:30:42

您必须指定该友元是模板函数:

MyClass<T>& operator+=<>(const MyClass<T>& classObj);

请参阅此 C++ FAQ Lite 答案以获取详细信息。

You must specify that the friend is a template function:

MyClass<T>& operator+=<>(const MyClass<T>& classObj);

See this C++ FAQ Lite answer for details.

┼── 2024-10-06 11:30:42

这种方式有效:

class A
{
    struct Wrap
    {
        A& a;
        Wrap(A& aa) aa(a) {}
        operator int() { return a.value; }
        operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    }
    Wrap operator*() { return Wrap(*this); }
};

This way works:

class A
{
    struct Wrap
    {
        A& a;
        Wrap(A& aa) aa(a) {}
        operator int() { return a.value; }
        operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    }
    Wrap operator*() { return Wrap(*this); }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文