我在模板类中有多个 * 运算符的重载。为什么按不同的顺序放置声明会得到不同的结果?

sta*_*ame 6 c++ templates overloading class friend

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

#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);
}
Run Code Online (Sandbox Code Playgroud)

这有效,但如果我改变:

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

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

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

产生错误的代码:

Example<int> a(2);
2 * a;
Run Code Online (Sandbox Code Playgroud)

错误:

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   
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/j4zYTP8n7

HTN*_*TNW 5

operator*您的代码中有两个不同的名称。有您在 之前声明的函数模板Example,以及 的成员函数Example。语法operator*<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);
};
Run Code Online (Sandbox Code Playgroud)

做它的其他方式,而是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...
};
Run Code Online (Sandbox Code Playgroud)


sta*_*ame 1

在您的帮助下,我找到了以下解决方案。我还能够摆脱第一行中多余的声明。这是最终产品:

template<typename T>
class Example
{
private:
    T m_data;
public:
    Example(T);

    Example operator*(const T& other);

    template<typename T>
    friend Example<T> operator*(T, Example<T>);
};

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);
}
Run Code Online (Sandbox Code Playgroud)