如何使用模板函数设置不同类型的值

How to use template function to set values with different types?

本文关键字:同类型 设置 函数 何使用      更新时间:2023-10-16

大家好!

我有一个名为UpdateValue的模板函数,它旨在更新一些不同类型的值,如integer、BOOL、string等。请参阅以下代码片段供您参考:

#include <typeinfo.h>
template<class T> 
void UpdateValue(T Value)
{   
if ( typeid(int) == typeid(Value) ) 
{  
ZOrder(Value);
}
else if ( typeid(bool) == typeid(Value) )
{  
BOOL bShow = Value ? TRUE : FALSE;
Show(bShow);
}
else if ( typeid(CString) == typeid(Value) )
{  
Theme(Value);
}
}
void Show(BOOL bShow) { m_bShow = bShow; }
void ZOrder(int nZOrder) { m_nZOrder = nZOrder; }
void Theme(CString strTheme) { m_strTheme = strTheme; }
BOOL m_bShow;
int m_nZOrder;
CString m_strTheme;

但是当我使用以下语句调用这种模板函数时

CString strValue = _T("Animal");
UpdateValue<CString>(strValue);

上述代码由于抛出以下异常而编译失败:

e:\dynprop\dynprop\mainfrm.cpp(269):错误C2664:"CMainFrame::ZOrder":无法将参数1从"CString"转换为"int"1> 没有用户定义的可执行此转换的转换运算符,或者无法调用该运算符1> e:\dynprop\dynprop\mainfrm.cpp(67):请参阅对正在编译的函数模板实例化"void CMainFrame::UpdateValue(T)"的引用1> 与1>[1> T=C字符串1> ]

你能告诉我如何计算吗?提前谢谢!

您并没有真正使用模板工具。或者更确切地说,错过了使用它。发生的情况是,您将ZOrder(Value)称为void UpdateValue(T Value),并将其实例化,其中T的每一次出现都将按照您的指定替换为CString。但仅此而已。

功能看起来像这个

void UpdateValue(CString Value)
{   
if ( typeid(int) == typeid(Value) ) 
{  
ZOrder(Value);
}
else if ( typeid(bool) == typeid(Value) )
{  
BOOL bShow = Value ? TRUE : FALSE;
Show(bShow);
}
else if ( typeid(CString) == typeid(Value) )
{  
Theme(Value);
}
}

在模板被实例化后,正常的编译工作就会发生。。。并且您得到一个错误,因为它被写为ZOrder(Value);,其中valueCString类型。这将产生错误,即使在这种情况下使用RTTI,也不应该到达该调用路径。

您应该做的是使用专门化来处理不同的类型。尝试用以下内容替换UpdateValue的原始定义:

template<> // specialization when T is get to be int
void UpdateValue<int>(int Value) { ZOrder(Value);};
template<> // specialization when T is get to be CString
void UpdateValue<bool>(bool Value) { BOOL bShow = Value ? TRUE : FALSE; Show(bShow);};
template<> // specialization when T is get to be CString
void UpdateValue<CString>(CString Value) { Theme(Value);};
template<class T>  //general case
void UpdateValue(T Value) { cout << "IMPLEMENT MEn";};

然后,当您调用UpdateValue< T >时,您将调用具有适当主体的版本。此外,您也不必使用RTTI。

更新:在评论者的建议之后。如果你不需要/不想处理一般情况(即未知类型),你可以求助于普通重载并使用:

//Value is int
void UpdateValue(int Value) { ZOrder(Value);};
//Value is bool
void UpdateValue(bool Value) { BOOL bShow = Value ? TRUE : FALSE; Show(bShow);};
//Value is CString
void UpdateValue(CString Value){ Theme(Value);};

甚至不需要模板!

正如其他答案中所述(或暗示)的那样,您需要将三个代码分支分离为三个模板专门化-每个参数类型一个。但这将是愚蠢的;如果你真的想有一个UpdateValue函数,根据参数类型做三件不同的事情,只需编写UpdateValue的三个重载,并且根本不使用模板!

(使用BOOL类型可能不起作用,因为它可能也是int。你很可能应该使用bool,除非有一些非常强烈和奇怪的理由。)

你可以使用函数重载来实现你想要做的事情,我认为,(我把它改为使用STL字符串,这样我就可以编译它了):

#include <typeinfo>
#include <string>
using namespace std;
bool m_bShow;
int m_nZOrder;
string m_strTheme;
void Show(bool bShow) { m_bShow = bShow; }
void ZOrder(int nZOrder) { m_nZOrder = nZOrder; }
void Theme(string strTheme) { m_strTheme = strTheme; }
void DoUpdate( bool bShow )
{
Show( bShow );
}
void DoUpdate( int nZOrder )
{
ZOrder( nZOrder );
}
void DoUpdate( string strTheme )
{
Theme( strTheme );
}
template<class T>
void UpdateValue(T Value)
{
DoUpdate( Value );
}
int main( int argc, char **argv )
{
string strValue = "Animal";
UpdateValue<string>(strValue);
return 0;
}

即使是死代码,代码仍在编译中。所以你说:

if ( typeid(int) == typeid(Value) )
{  
ZOrder(Value);
}

它仍然试图编译代码,即使它永远不会执行,所以它抛出了错误。

你最好使用模板专业化:

template<class T> 
void UpdateValue(T Value) {
// By default, do nothing.
}
void UpdateValue < int >(int value) {
ZOrder(value);
}
void UpdateValue < bool >(bool value) {
BOOL bShow = Value ? TRUE : FALSE;
Show(bShow);
}
void UpdateValue < CString >(CString value) {
Theme(value);
}

总之,这是对模板的不必要使用。你最好使用几个重载。

如前所述,UpdateValue<CString>(CString)实例化失败,因为它无法编译ZOrder(CString)表达式。记住,模板实例化只是编译时类型替换,而不是运行时。混合运行时RTTI和模板不是一个好主意,看起来像是模板滥用。

建议使用函数重载而不是模板,它会产生相同的结果:

void UpdateValue(int Value)
{
ZOrder(Value);
}     
void UpdateValue(bool Value)
{
BOOL bShow = Value ? TRUE : FALSE;        
Show(bShow);     
}
void UpdateValue(const CString& Value)
{
Theme(Value);
}