0

everyone!

I have a template function named UpdateValue, which was designed to update some values with different types such as integer, BOOL, string, and so on. Please see the following code snippet for your reference:

#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;

But when I use the following statements to call this kind of template function

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

the aforesaid code failed to compile by throwing the following exceptions:

e:\dynaprop\dynaprop\mainfrm.cpp(269) : error C2664: 'CMainFrame::ZOrder' : cannot convert parameter 1 from 'CString' to 'int' 1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 1> e:\dynaprop\dynaprop\mainfrm.cpp(67) : see reference to function template instantiation 'void CMainFrame::UpdateValue(T)' being compiled 1> with 1> [ 1> T=CString 1> ]

Would you please show me how to figure it out? Thank you in advance!

5
  • 2
    You call ZOrder(Value) when Value is a CString and ZOrder takes an int. Commented Sep 26, 2012 at 16:18
  • Thank you chris.Doesn't the typeid take effect in the template function? I want to use "if ... then" condition block as well as typeid to prevent calling ZOrder and Show function when I use UpdateValue<CString>("Animal") to modify a string by calling Theme function. Commented Sep 26, 2012 at 16:30
  • 1
    You might want to research template specialization. Commented Sep 26, 2012 at 16:31
  • @GoldenLee, typeid is a runtime operation, as well as code based on an if. The compiler parses every runtime aspect, so only compile-time comparisons can stop it from looking at that call. Template specialization is most likely what you want here. Commented Sep 26, 2012 at 16:45
  • @chris: Thank you. I made a mistake in underestanding the typeid's runtime mechanism. I possbly use overloaded functions to solve my problems instead. Commented Sep 26, 2012 at 16:56

5 Answers 5

1

You are not really using the template facilities. Or rather miss using it. What happens is you call the ZOrder(Value) the void UpdateValue(T Value) get instantiated where every occurence of T gets replaced with CString as you specified. But that is all.

The function look like this

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);
    }
}

After the template gets instantied the normal compiling stuff happens ... and you get an error 'cause it is written ZOrder(Value); where value is of CString type. This will produce an error, even though utilizing RTTI this call path should never be reached in such case.

What you should do is to use specializations to handle different types. Try replacing original definition of UpdateValue with these:

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 ME\n";};

Then when you call UpdateValue< T > you invoke version with appropriate body. also you don't have to use RTTI.

UPDATE: After the commenter suggestion. If you do not need/want to the handle general case (i.e. unknown type), you can resort to plain overloads and go with:

//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);};

No need even for templates then!

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you luk32! I see. But any alternative solutions?
@GoldenLee Use overloads instead of templates. See another answers for examples.
@luk32: I'll take your advice, and use overloads instead. Thank you!
@GoldenLee Well, it was Rost's suggestion I updated my answer to make it most complete I could.
0

As stated (or implied) in some other answers, you would need to separate your three code branches into three template specializations - one for each parameter type. But this would be silly; If you really want to have a single UpdateValue function that does three different things depending on the argument type, just write three overloads of UpdateValue and don't use a template at all!

(This may not work using the BOOL type, since it's probably an int as well. You should most likely be using bool instead, unless there's some REALLY strong - and strange - reason to do otherwise.)

Comments

0

You could use function overloading to achieve what you're trying to do I think, (I changed it to use STL string so I can get it compiling):

#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;
}

4 Comments

Why do you need template here? It's useless and excessive. Overloads are enough. And explicit argument type call is weird too - let the compiler do its work with arguments types deduction.
@nemasu: Thank you! I just show my problem by using the simplest code. My production code is quite complicated. If I write a DoUpdate function for each data type, there is a lot of duplicate codes written. Anyway, thank you very much!
@Rost Obviously you don't need a template with this little snippet of code, but I have a feeling that this isn't the whole program. I'm just giving advice on how to solve the problem while using existing code.
@nemasu: Yes! Thank you for having taken you valuable time.
0

The code is still compiled, even though it's dead code. So where you say:

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

It still attempts to compile the code even though it will never execute, so it throws the error.

You're better off using template specialization:

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);
}

This is an unnecessary use of templates, all told. You're better off using several overloads instead.

Comments

0

As previous answers and comments mentioned, UpdateValue<CString>(CString) instantiation fails, because it could not compile ZOrder(CString) expression. Remember, template instantiation is just compile-time type substitution, not run-time. Mixing run-time RTTI and templates is not good idea and looks like templates misusing.

Suggest to use function overloading instead of template, it will produce the same result:

void UpdateValue(int Value)
{
    ZOrder(Value);
}     

void UpdateValue(bool Value)
{
   BOOL bShow = Value ? TRUE : FALSE;        
   Show(bShow);     
}

void UpdateValue(const CString& Value)
{
   Theme(Value);
} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.