C++-模板类中模板函数的单独声明/定义

C++ - Separate declaration/definition for template function in template class

本文关键字:声明 定义 单独 函数 C++-      更新时间:2023-10-16

我知道在头中声明模板类方法并在源文件中定义它的语法如下:

myclass.h

template <typename T>
class MyClass {
public:
void method(T input);
private:
T privVar;
};

myclass.cpp

template <typename T>
void MyClass<T>::method(T input) {
privVar = input;
}

但是,如果该方法也是一个模板呢?我正在向basic_string类添加方法,我想知道如何编写函数的实现。

MyString.h

template <class _Elem   = TCHAR,
class _Traits = std::char_traits<_Elem>,
class _Ax     = std::allocator<_Elem>>
class String
: public std::basic_string<_Elem, _Traits, _Ax> {
private:
// Types for the conversion operators.
typedef       _Elem* _StrTy;
typedef const _Elem* _ConstStrTy;
//...
public:
// Conversion operators so 'String' can easily be
// assigned to a C-String without calling 'c_str()'.
operator _StrTy() const {
return const_cast<_StrTy>(this->c_str());
}
operator _ConstStrTy() const {
return this->c_str();
}
// ... Constructors ...
/*------------ Additional Methods ------------*/
//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val);
//! Converts a string to the given type.
template <class _ValTy> static _ValTy ConvertTo(const String& str);
template <class _ValTy> _ValTy ConvertTo(void) const;
//! Checks if a string is empty or is whitespace.
static bool IsNullOrSpace(const String& str);
bool IsNullOrSpace(void) const;
//! Converts a string to all upper-case.
static String ToUpper(String str);
void ToUpper(void);
// ...
};

如何实现template <class _ValTy> static String ConvertFrom(_ValTy val);?因为现在我不仅需要指定类模板,还需要指定函数模板。我打赌我要写的代码是无效的,但它应该显示我正在努力实现的目标:

MyString.cpp

template <class _Elem, class _Traits, class _Ax>
template <class _ValTy>
String<_Elem, _Traits, _Ax> String<_Elem, _Traits, _Ax>::ConvertFrom(_ValTy val) {
// Convert value to String and return it...
}

我对模板一点也不了解。我不仅非常怀疑上面的内容是否有效,而且写起来似乎很麻烦,可读性也不强。我该如何实现模板方法,以及返回自己类类型的静态模板方法?因为我不想在标题中定义它们。

模板外的模板成员函数定义语法如下:

template <class T> struct A
{
template <class X> void f();
};
template<class T> template<class X> void A<T>::f()
{
}

所以你的代码是正确的。

需要注意的是,在.cpp中定义模板成员并不是很有用。在这种情况下,您应该使用需要与此模板一起使用的所有类型来显式实例化它们。或者不要在.cpp之外使用它们,这是没有意义的。

在回答您的问题之前,让我先说:不要这样做。通过使用自由函数来扩展std::string,就像标准库实现许多算法一样。此外,我建议只针对范围而不是strings进行此操作,但这更主观。

还要注意,std::string避免隐式转换为C字符串,这不是为了让您的生活更艰难,而是为了保护您的代码免受意外隐式转换可能导致的各种晦涩错误的影响。我会花很长时间认真考虑实施它们。想想看:当你写代码的时候,你需要额外的一些时间来键入.c_str()一次,在接下来的时间里,任何读过你代码的人都会立即知道它被用作C风格的字符串,而不是std::string

要回答您的问题,只需将代码放在标题中:

//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val)
{
// Code here
}

最后请注意,以下划线+大写字母开头的标识符(以及以_开头的许多其他内容)是为编译器保留的,因此,对于程序的功能,所有的赌注都是不确定的。

您的函数定义是有效的,不能在类声明之外以不那么详细的方式定义它。由于您想将函数定义放在.cpp文件中,因此无法利用将函数定义与更简洁的函数声明相结合的优势。通过将函数定义放在.cpp文件中,您还必须显式实例化模板类的所有所需专业化。

下面是Rost和Josh答案的示例代码:

template.hpp

#pragma once
template<class T>
class Add
{
public:
T Addition(T summand1, T summand2);
};
void AddUsing( int summand1, int summand2 );

template.cpp

#include "template.hpp"
#include <iostream>
template<class T>
T Add<T>::Addition(T summand1, T summand2)
{
return summand1 + summand2;
}
void AddUsing( int summand1, int summand2 )
{
std::cout << Add<int>().Addition( summand1, summand2 ) << std::endl;
}

main.cpp

#include "template.hpp"
int main()
{
AddUsing ( 2, 2 );
}