我正在编写以下模板化向量类。
向量.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;
};
我完全不知道为什么会发生这种情况。
我尝试删除模板,问题消失了,所以它一定是相关的。
一般来说,模板函数的定义不应放在单独的
.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