在 C++ 中使用模板更改运算符顺序时出错

问题描述 投票:0回答:1

我正在编写以下模板化向量类。

向量.h:

#ifndef INCLUDE_HEADERS_VECTORS_H
#define INCLUDE_HEADERS_VECTORS_H

template<class Scalar> class Vector2D;
template<class Scalar> Vector2D<Scalar> operator+(Scalar a, Vector2D<Scalar> v);

template<class Scalar>
class Vector2D {
    public:
        Vector2D();
        Vector2D(Scalar a, Scalar b);

        Scalar getX();
        Scalar getY();

        Vector2D<Scalar> operator+(Scalar a);        
        friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
        
    private:
        Scalar x, y; 

};

#endif 

向量.cpp:

#include<headers/vectors.h>

template<class Scalar>
Vector2D<Scalar>::Vector2D() {
    x = 0;
    y = 0;
}

template<class Scalar>
Vector2D<Scalar>::Vector2D(Scalar a, Scalar b) {
    x = a;
    y = b;
}

template<class Scalar>
Scalar Vector2D<Scalar>::getX() {
    return x;
}

template<class Scalar>
Scalar Vector2D<Scalar>::getY() {
    return y;
}

template<class Scalar>
Vector2D<Scalar> Vector2D<Scalar>::operator+(Scalar a) {
    return Vector2D<Scalar>(a + x, a + y);
}

template<class Scalar>
Vector2D<Scalar> operator+(Scalar a, Vector2D<Scalar> v) {
    return Vector2D<Scalar>(a + v.x, a + v.y);
}

template class Vector2D<float>;
template Vector2D<float> operator+<float>(float a, Vector2D<float> v);

主要.cpp:

#include<headers/vectors.h>
#include<iostream>

int main(int argc, char* argv[]){
    Vector2D<float> a(1.0, 3.0);
    std::cout<<a.getX()<<" "<<a.getY()<<std::endl;

    a = (float)2.0 + a;
    std::cout<<a.getX()<<" "<<a.getY()<<std::endl;

    a = a + (float)-2.0;
    std::cout<<a.getX()<<" "<<a.getY()<<std::endl;

    return 0;
}

当我尝试在 Windows 上使用 g++ 编译它时,出现以下错误:

g++ -Iinclude -Iinclude/SDL2 -Iinclude/headers -Llib -o Main src/*.cpp -lmingw32 -lSDL2main -lSDL2 -lSDL2_image
In file included from src/Main.cpp:2:
include/headers/vectors.h:29:33: error: declaration of 'operator+' as non-function
   29 |         friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
      |                                 ^~~~~~~~
include/headers/vectors.h:29:41: error: expected ';' at end of member declaration
   29 |         friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
      |                                         ^
      |                                          ;
include/headers/vectors.h:29:43: error: expected unqualified-id before '<' token
   29 |         friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
      |                                           ^
In file included from src/vectors.cpp:1:
include/headers/vectors.h:29:33: error: declaration of 'operator+' as non-function
   29 |         friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
      |                                 ^~~~~~~~
include/headers/vectors.h:29:41: error: expected ';' at end of member declaration
   29 |         friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
      |                                         ^
      |                                          ;
include/headers/vectors.h:29:43: error: expected unqualified-id before '<' token
   29 |         friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
      |                                           ^
src/vectors.cpp:70:18: error: non-class, non-variable partial specialization 'operator+<Scalar>' is not allowed
   70 | Vector2D<Scalar> operator+<Scalar>(Scalar a, Vector2D<Scalar> v) {
      |                  ^~~~~~~~~~~~~~~~~
src/vectors.cpp: In instantiation of 'Vector2D<Scalar> operator+(Scalar, Vector2D<Scalar>) [with Scalar = float]':
src/vectors.cpp:96:69:   required from here
src/vectors.cpp:71:35: error: 'float Vector2D<float>::x' is private within this context
   71 |     return Vector2D<Scalar>(a + v.x, a + v.y);
      |                                 ~~^
include/headers/vectors.h:37:16: note: declared private here
   37 |         Scalar x, y;
      |                ^
src/vectors.cpp:71:44: error: 'float Vector2D<float>::y' is private within this context
   71 |     return Vector2D<Scalar>(a + v.x, a + v.y);
      |                                          ~~^
include/headers/vectors.h:37:19: note: declared private here
   37 |         Scalar x, y;
      |                   ^
mingw32-make: *** [MakeFile:2: all] Error 1

但是,如果我更改 vectors.h 中 + 运算符声明的顺序,如下所示,它将正常工作。

#ifndef INCLUDE_HEADERS_VECTORS_H
#define INCLUDE_HEADERS_VECTORS_H

template<class Scalar> class Vector2D;
template<class Scalar> Vector2D<Scalar> operator+(Scalar a, Vector2D<Scalar> v);

template<class Scalar>
class Vector2D {
    public:
        Vector2D();
        Vector2D(Scalar a, Scalar b);

        Scalar getX();
        Scalar getY();

        friend Vector2D<Scalar> operator+ <>(Scalar a, Vector2D<Scalar> v);
        Vector2D<Scalar> operator+(Scalar a);        
        
        
    private:
        Scalar x, y; 

};

我完全不知道为什么会发生这种情况。

我尝试删除模板,问题消失了,所以它一定是相关的。

c++ templates g++
1个回答
0
投票

一般来说,模板函数的定义不应放在单独的

.cpp
文件中。相反,它们应该在模板中的
.h
文件中定义。这个答案消除了
.cpp
文件。

这避免了到处不断重复

template< typename Scalar >
的麻烦。更重要的是,它允许编译器自动内联它们。

此外,

operator+
还有一个习惯用法,即首先定义
operator+=
,然后将
operator+
实现为隐藏好友,从而调用
operator+=
。见下文。

// vectors.h
#ifndef INCLUDE_HEADERS_VECTORS_H
#define INCLUDE_HEADERS_VECTORS_H

template<class Scalar>
class Vector2D
{
    Scalar x{};  // default member-initialization sets x to 0
    Scalar y{};  // default member-initialization sets y to 0
public:
    Vector2D() = default;
    Vector2D(Scalar a, Scalar b)
        : x{ a }  // use base-member initization, rather than assignment.
        , y{ b }
    {}

    Scalar getX() const  // "getter" function declared with const
    {
        return x;
    }

    Scalar getY() const  // "getter" function declared with const
    {
        return y;
    }

    // Compound assignment operator returns a reference to `this` object.
    // Within its definition, class template `Vector2D` does not need 
    // a template argument. Avoid `Vector2D<Scalar>`.
    Vector2D& operator+= (Vector2D const& v)
    {
        x += v.x;
        y += v.y;
        return *this;
    }

    // Use hidden friend idiom to define `operator+`.
    // Left operand is a value parameter.
    friend Vector2D operator+ (Vector2D a, Vector2D const& b)
    {
        return a += b;
    }

    // As before, compound assignment operator returns a reference to 
    // `this` object. Within its definition, class template `Vector2D` 
    // does not need a template argument. Avoid `Vector2D<Scalar>`.
    Vector2D& operator+= (Scalar a)
    {
        x += a;
        y += a;
        return *this;
    }

    // Provide two versions of `operator+` for Scalar operand. 
    // That way, the Scalar can appear on either side of the `+` sign.
    // Once again, these are hidden friends.
    // The vector is passed by value.
    friend Vector2D operator+ (Scalar const a, Vector2D v) { return v += a; }
    friend Vector2D operator+ (Vector2D v, Scalar const a) { return v += a; }
};

#endif 
// end file: vectors.h

输出

文件

main.cpp
与OP相比没有变化。

1 3
3 5
1 3
© www.soinside.com 2019 - 2024. All rights reserved.