繁体   English   中英

当模板类型的行为相同时,定义模板类的成员函数的正确方法是什么?

[英]What is the proper way to define a templated class's member function when behavior is identical for template types?

弄清楚是否有东西坏了,我就把它弄坏了,我决定专门研究一个我拥有的类,以便可以自动在float和double precision之间建立模板。

我有以下[简化]类声明:

// 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类型指定功能的完全专业化。


问题

假定对于任何原子输入类型(浮点,双精度,甚至整数等),行为都是相同的,并且仅影响答案的精度。

有没有一种方法可以强制编译器不必为它们全部发出专门化的代码;

  1. 将所有函数定义移到头文件中,或者
  2. 显式地为所有可能涉及大量copypasta的数据类型创建专门化设计?

推荐链接


推荐做法

而不是从在.cpp到头部移动的定义,重命名的.cpp.tpp和添加#include "Quatcam.tpp"Quatcam.h的末尾。

这是通常拆分模板声明及其定义的方式,同时仍具有可用于实例化的定义。

注意 :如果您遵循这条道路,则不应像使用.cpp一样自行编译.tpp


显式实例化

您可以在.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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM