Here is a running example of what I want to achieve:
#include <iostream>
#include <string>
#include <typeinfo>
template <class T>
struct print
{
static void function( T thing)
{
std::cout << thing << std::endl;
}
};
template <class T>
struct printMore
{
static void function( T thing )
{
std::cout << thing << " and more" << std::endl;
}
};
struct dynamicBase
{
const char* m_value;
size_t getType()
{
switch( *m_value )
{
case '0': //the string is going to be a small script, the type returned is known during execution but not at compile time
return typeid( int ).hash_code();
case '1':
return typeid( float ).hash_code();
}
return typeid( const char* ).hash_code();
}
template<class T>
T* tryGetValue()
{
if( getType() == typeid( T ).hash_code() )
return (T*) ( &( m_value[1] ) ); //dumb example, actually I'll evaluate the string as script and return a value based on that
else
return nullptr;
}
void applyPrint( )
{
if( int* t = tryGetValue<int>() )
print<int>::function( *t ); //I can cout an int so this line compile
else if( float* t = tryGetValue<float>() )
print<float>::function( *t ); //I can cout a float so this one too
else
print<const char*>::function( *tryGetValue<const char*>() ); //same
}
void applyPrintMore()
{
if( int* t = tryGetValue<int>() )
printMore<int>::function( *t );
else if( float* t = tryGetValue<float>() )
printMore<float>::function( *t );
else
printMore<const char*>::function( *tryGetValue<const char*>() ); //same
}
//.... applyprintPretty, applyprintInRed, applyprintInBlue, .....
};
int main()
{
dynamicBase d;
d.m_value = "0a\0\0\0";
d.applyPrint(); //97 == ascii value of 'a'
__asm {nop}; //for breakpoint purpose
}
At first I though I could use a template like this :
template<class myFunctionClass>
void applyPrint( )
{
if( int* t = tryGetValue<int>() )
myFunctionClass<int>::function( *t );
else if( float* t = tryGetValue<float>() )
myFunctionClass<float>::function( *t );
else
myFunctionClass<const char*>::function( *tryGetValue<const char*>() );
}
And then realized my mistake (templated types are not types until you give them template parameters). But is there a way to refactorize this code so I don't have 15 applyStuff functions? (I'm doing it wrong, am I not?)
You're looking for template template parameters:
template<template <typename> class myFunctionClass>
void applyPrint( )
{
if( int* t = tryGetValue<int>() )
myFunctionClass<int>::function( *t );
else if( float* t = tryGetValue<float>() )
myFunctionClass<float>::function( *t );
else
myFunctionClass<const char*>::function( *tryGetValue<const char*>() );
}
You can find a reference here: "cppreference.com - Template template parameters".
Template template parameters are the answer.
template<template <typename> class myFunctionClass>
void apply( )
{
if( int* t = tryGetValue<int>() )
myFunctionClass<int>::function( *t );
else if( float* t = tryGetValue<float>() )
myFunctionClass<float>::function( *t );
else
myFunctionClass<const char*>::function( *tryGetValue<const char*>() );
}
// ...
apply<print>();
apply<printMore>();
For no good reason, they must always say "class" instead of "typename" (though C++ 17 fixes this). The inner set of parameters (here, the bare keyword typename) must be equal in number and kind to the number of parameters that the template uses, though they need not be given names.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With