当模板类型的行为相同时,定义模板化类的成员函数的正确方法是什么?
What is the proper way to define a templated class's member function when behavior is identical for template types?
考虑到如果没有破坏,我会破坏它,我决定专门化一个类,以便它可以在float和双精度之间自动模板化。
我有下面的[简化]类声明:
// Quatcam.h
#pragma once
#include <boost/math/quaternion.hpp>
#include <boost/numeric/ublas/matrix.hpp>
template<typename FloatType>
class QuaternionCamera
{
public:
QuaternionCamera();
void applyTranslation(boost::numeric::ublas::vector<FloatType> translationVector);
boost::numeric::ublas::matrix<FloatType> getTranslationMatrix();
protected:
boost::numeric::ublas::vector<FloatType> m_location;
boost::math::quaternion<FloatType> m_orientation;
};
我已经在.cpp文件中定义了成员函数:
//Quatcam.cpp
#include "Quatcam.h"
using namespace boost::numeric::ublas;
template<typename FloatType>
QuaternionCamera<FloatType>::QuaternionCamera()
: m_location(3),
m_orientation(1,0,0,0)
{
m_location[0] = m_location[1] = m_location[2] = 0;
}
template<typename FloatType>
void QuaternionCamera<FloatType>::applyTranslation(boost::numeric::ublas::vector<FloatType> translationVector)
{
m_location += translationVector;
}
template<typename FloatType>
boost::numeric::ublas::matrix<FloatType> QuaternionCamera<FloatType>::getTranslationMatrix()
{
boost::numeric::ublas::matrix<FloatType> returnMatrix = boost::numeric::ublas::identity_matrix<FloatType>(4,4);
boost::numeric::ublas::vector<FloatType> invTrans = -m_location;
returnMatrix(3,0) = invTrans[0];
returnMatrix(3,1) = invTrans[1];
returnMatrix(3,2) = invTrans[2];
return returnMatrix;
}
此代码本身将愉快地编译成.lib或.obj文件,但试图在原位使用类会导致链接器错误。下面是我的示例main.cpp试图使用类:
#include "Quatcam.h"
#include <boost/numeric/ublas/io.hpp>
#include <iostream>
int main(int argc, char** argv)
{
QuaternionCamera<float> qcam;
boost::numeric::ublas::vector<float> loc(3);
loc[0] = 0;
loc[1] = 5;
loc[2] = 0;
qcam.applyTranslation(loc);
boost::numeric::ublas::matrix<float> qtm = qcam.getTranslationMatrix();
std::cout << "qtm: "<< qtm << std::endl;
return 0;
}
此代码链接失败,因为getTranslationMatrix和applyTranslation缺少符号。我认为这是因为我没有在技术上为float类型指定完整的函数专门化。
问题(s)
给定任何原子输入类型(float, double,甚至int等…)的行为是相同的,并且只影响答案的精度。
是否有一种方法可以强制编译器为它们发出特化而不必;
- 将所有函数定义移动到头文件中,或者;
- 显式地为所有数据类型创建专门化,这可能涉及大量的复制?
推荐链接
- 为什么模板只能在头文件中实现?为什么c++模板定义需要在头文件中?
推荐作法
与其将定义从.cpp移到头文件中,不如将.cpp重命名为。tpp,并在Quatcam.h结尾添加#include "Quatcam.tpp"
。
这就是您通常拆分模板声明及其定义的方式,同时仍然有可用于实例化的定义。
注意:如果你遵循这条路,你不应该单独编译.tpp
,就像你编译.cpp
一样。
显式实例化
您可以在.cpp中显式实例化所讨论的模板,以便为链接器提供它们,但这要求您知道需要实例化的确切类型。
这意味着如果您只显式实例化QuaternionCamera<float>
,如果main.cpp试图使用QuaternionCamera<double>
,您仍然会得到链接器错误。
没有办法强制实例化所有"原子输入类型",您必须显式地将它们全部写出来。
template class QuaternionCamera<float>; // explicit instantiation
template class QuaternionCamera<double>; // etc, etc...
应该把这些函数放在头文件中,而不是放在.cpp源代码中。
编译器只在模板实参推导完成后才创建函数实例化。生成的目标文件将包含针对模板所使用的每种类型的编译函数。
但是,.cpp文件是单独编译的。因此,当您编译Quatcam.cpp时,编译器不会为该类型找到任何实例化,也不会创建函数体。这就是为什么会出现链接器错误。
简单地说,你的标题应该是这样的:
template<typename T>
class Foo {
void Print();
T data;
};
// If template arguments are specified, function body goes to .cpp
template<>
void Foo<float>::Print();
// Template arguments are incomplete, function body should remain in the header
template<typename T>
void Foo<T>::Print() {
std::cout << data;
}
这应该是。cpp的源代码:
template<>
void Foo<float>::Print() {
std::cout << floor(data);
}
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针