首页 > 解决方案 > 我在模板类中有多个 * 运算符的重载。当我将声明以不同的顺序放置时,为什么会得到不同的结果?

问题描述

我有一个需要多个 * 运算符重载的类。其中一些需要声明为朋友,以便我可以将类类型作为第二个参数。这是一个遇到我即将提出的问题的类的示例:

#pragma once

template<typename T>
class Example;

template<typename T>
Example<T> operator*(T value, Example<T> obj);

template<typename T>
class Example
{
private:
    T m_data;
public:
    Example(T);
    friend Example operator*<T>(T, Example);
    Example operator*(const T& other);

};

template<typename T>
Example<T> operator*(T value, Example<T> obj)
{
    return value * obj.m_data;
}

template<typename T>
Example<T>::Example(T data) :m_data(data) { }

template<typename T>
 Example<T> Example<T>::operator*(const T& other)
{
    return Example(m_data * other.m_data);
}

这有效,但如果我改变:

template<typename T>
class Example
{
private:
    T m_data;
public:
    Example(T);
    friend Example operator*<T>(T, Example);
    Example operator*(const T& other);
};

template<typename T>
class Example
{
private:
    T m_data;
public:
    Example(T);
    Example operator*(const T& other);
    friend Example operator*<T>(T, Example);
};

即使我所做的只是交换包含运算符重载声明的那两行,我也开始收到一堆错误。你能解释一下这里发生了什么吗?这对我来说毫无意义。

产生错误的代码:

Example<int> a(2);
2 * a;

错误:

unexpected token(s) preceding';'  
syntax error missing':' before '<'  
'operator*': redefinition: previous definition was 'function'  
'operator*': looks like a function but there is no parameter list.  
'*': uses 'Example<int>' which is being defined  
'*': friend not permitted on data declarations   

https://godbolt.org/z/j4zYTP8n7

标签: c++classtemplatesoverloadingfriend

解决方案


您的代码中有两种不同的名称operator*。有你之前声明的函数模板,Example以及 的成员函数Example。syntaxoperator*<T>是一种模板特化,仅在operator*引用模板时有效,对成员函数无效。在您的第一个声明中,在friend成员函数之前,operator*成员函数尚未在编译器看到的位置声明operator*<T>,因此它将名称解析为之前声明的函数模板Example,一切都很好(具体的特化operator*<T>变成friend了每个Example<T>)。

template<typename T>
Example<T> operator*(T value, Example<T> obj); // <-\ ...finds a template, so no syntax error
                                               //   |
template<typename T>                           //   |
class Example {                                //   |
    T m_data;                                  //   |
public:                                        //   |
    Example(T);                                //   |
    friend Example operator*<T>(T, Example);   // >-/ looking up this name...
    Example operator*(const T& other);
};

以另一种方式进行操作,而是operator*<T>引用不是模板的成员函数,并且您会收到语法错误(具体来说,我认为它试图以某种方式将其解释为operator* < T >实际<小于>/大于运算符)。

template<typename T>
class Example {
    T m_data;
public:
    Example(T);
    Example operator*(const T& other);       // <-\ ...does not find a template; ouch!
    friend Example operator*<T>(T, Example); // >-/ looking up this name...
};

推荐阅读