Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using unspecialized templated type as template parameter [duplicate]

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?)

like image 842
Nyashes Avatar asked Mar 15 '17 18:03

Nyashes


2 Answers

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".

like image 69
Vittorio Romeo Avatar answered Sep 18 '22 13:09

Vittorio Romeo


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.

like image 24
DrPizza Avatar answered Sep 18 '22 13:09

DrPizza