Avoid switching on template parameters

前端 未结 3 921
情书的邮戳
情书的邮戳 2021-01-24 18:02

Simplified I have the following class hierarchy:

class BaseVec {
  public:
    BaseVec() {};
    virtual ~BaseVec() {};

    virtual double get_double(int i) con         


        
3条回答
  •  借酒劲吻你
    2021-01-24 18:59

    First of all, don't use reinterpret_cast while converting to/from pointer to polymorphic class. You can write a simple pointer wrapper which allow you to use safe casting operator static_cast:

    template 
    class PointerWrapper
    {
    public:
    
        PointerWrapper(Type* object);
        PointerWrapper& operator=(Type* object);
        Type* operator->();
    
    protected:
    
        Type* object;
    
    };
    
    template 
    PointerWrapper::PointerWrapper(Type* object) :
        object(object)
    {
    }
    
    template 
    PointerWrapper& PointerWrapper::operator=(Type* object)
    {
        this->object = object;
    }
    
    template 
    Type* PointerWrapper::operator->()
    {
        return object;
    }
    

    Now you can write:

    typedef PointerWrapper BaseVecPointer;
    
    template
    double foo(void* p) {
        BaseVecPointer* vp = static_cast(p);
        // ...
        // ... = (*vp)->get_double(...);
        // ...
        return result;
    }
    

    In this code polymorphism capabilities were used, i.e. function get_double was called instead of calling get.

    But if you want to call just get, not get_double, i.e. you want to call template functions with different template arguments depending on the value of run-time variable, you can use the following method:

    enum FooTypes
    {
        NoFooType = -1,
        DoubleFooType = 0,
        IntegerFooType = 1,
        // ...
        FooTypesCount
    };
    
    template
    struct ChooseType
    {
        static
        const FooTypes value = NoFooType;
    
        typedef void Type;
    };
    
    template<>
    struct ChooseType
    {
        static
        const FooTypes value = DoubleFooType;
    
        typedef double Type;
    };
    
    template<>
    struct ChooseType
    {
        static
        const FooTypes value = IntegerFooType;
    
        typedef int Type;
    };
    

    Here you should write specializations of the class template ChooseType for all possible values of type variable. Following code describes the function ChooseFoo which selects what specialization of foo_template function template should be called:

    typedef double (*FooFunction)(void*);
    
    template
    FooFunction ChooseFooImpl(int type)
    {
        if (type == fooType)
        {
            if (ChooseType::value != NoFooType)
            {
                return foo_template::Type>;
            }
            else
            {
                return NULL;
            }
        }
        else
        {
            return ChooseFooImpl<(FooTypes)(fooType - 1)>(type);
        }
    }
    
    template<>
    FooFunction ChooseFooImpl(int type)
    {
        return NULL;
    }
    
    FooFunction ChooseFoo(int type)
    {
        return ChooseFooImpl(type);
    }
    

    And this is foo function implementation:

    double foo(void* p, int type)
    {
        FooFunction fooFunction = ChooseFoo(type);
    
        if (fooFunction != NULL)
        {
            return fooFunction(p);
        }
        else
        {
            //unsupported type
            // ...
        }
    }
    

提交回复
热议问题