0

This is more of a question of how the C++ compiler handles const typeid calls.

Hello! I am trying to make a tuple-style class, configured in such a way that I don't have to rewrite a bunch of the code with specializations.

So this is the general idea:

struct null_type{};

template <typename T1,typename T2=null_type,typename T3=null_type>
class ptestclass
{
private:
    template<typename K1,typename K2,typename K3>
    class barclass
    {
    public:
        static inline void bar(std::tuple<K1,K2,K3>& vals,K1* otherval1,K2* otherval2,K3* otherval3)
        {
            Foo(tr1::get<0>(vals),*otherval1);
            Foo(tr1::get<1>(vals),*otherval2);
            Foo(tr1::get<2>(vals),*otherval3);
        }
    };
    template<typename K1,typename K2>
    class barclass<K1,K2,null_type>
    {
    public:
        static inline void bar(std::tuple<K1,K2,null_type>& vals,K1* otherval1,K2* otherval2,null_type* otherval3)
        {
            Foo(tr1::get<0>(vals),*otherval1);
            Foo(tr1::get<1>(vals),*otherval2);
        }
    };
    template<typename K1>
    class barclass<K1,null_type,null_type>
    {
    public:
        static inline void bar(std::tuple<K1,null_type,null_type>& vals,K1* otherval1,null_type* otherval2,null_type* otherval3)
        {
            Foo(tr1::get<0>(vals),*otherval1);
        }
    };

    /*
     *Old Bar function...much more readable than bar class, but you cannot partially specialize
     *member functions of a class
     *
    void inline bar(std::tuple<T1,T2,T3> otherval)
    {
        if (typeid(T1) != typeid(null_type))//constant check hopfully optomized out
        {
            Foo(vals.get(1),otherval.get(1));
        }
        if (typeid(T2) != typeid(null_type))//constant check hopfully optomized out
        {
            Foo(vals.get(2),otherval.get(2));
        }
        if(typeid(T3) != typeid(null_type))//constant check hopfully optomized out
        {
            Foo(vals.get(3),otherval.get(3));
        }

    }
     */
    std::tuple<T1,T2,T3> vals;



    template<typename K>
    void static inline Foo(K& val,K& otherval)
    {
        //inlineable, short function that is called many (millions) of times per iteration
        val += otherval;
    }

    template<>
    void inline Foo<null_type>(null_type& val,null_type& otherval)
    {
        //inlineable, short function that is called many (millions) of times per iteration
        throw "Foo called on null type";
    }

public:
    ptestclass()
    {
        printf("made object");
    }
    void one_iteration(T1* otherval1,T2* otherval2,T3* otherval3,size_t count)
    {
        for (int i = 0; i < count; ++i)
        {
            barclass<T1,T2,T3>::bar(vals,otherval1+i,otherval2+i,otherval3+i);
        }
    }
};

//exposed public class with specialized one_iteration interfaces
template <typename T1,typename T2=null_type,typename T3=null_type>
class testclass : public ptestclass<T1,T2,T3>
{
public:
    void one_iteration(T1* otherval1,T1* otherval2,T1* otherval3,size_t count)
    {
        ptestclass::one_iteration(otherval1,otherval2,otherval3,count);
    }
};

template <typename T1>
class testclass<T1,null_type,null_type> : public ptestclass<T1,null_type,null_type>
{
public:
    void one_iteration(T1* otherval1,size_t count)
    {
        ptestclass::one_iteration(otherval1,NULL,NULL,count);
    }
};

So my question is is this optimization even possible within C++? If not, it will probably make more sense for me to use an inheritance model on the child nodes rather then a template at this level. However, I am trying to avoid the continual check of the number of types specified and the cost of indirection.

I'm going to start diving into the assembly to see if that is what the compiler does...Just in case this is not standardized behavior, I'm using the Microsoft Visual C++ Compiler 10.0.

Phil Miller
  • 36,389
  • 13
  • 67
  • 90
IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • 1
    you could use template specialization to implement the less than full versions of your tuple class. – EHuhtala Mar 19 '13 at 15:29
  • Member functions that you write implement in the interface itself are automatically declared "inline". Really no need to put the "inline" keyword there in this case. – Aleph Mar 19 '13 at 15:32
  • Yeah, I was thinking of going the template specialization rout, but I don't want to end up rewriting the "one_iteration" function based on the type. The existing code has the logic of the iteration being about 200 lines long, and multiple copies of that code would be difficult to maintain. Only the inner loop needs to be specialized by the calls...so maybe I need to specialize the "bar" function. However, I would think that a compiler worth its salt should see the typeid(T1) ~= typeid(null_type) is always true or false, and process it accordingly? – IdeaHat Mar 19 '13 at 15:59
  • Actually, @EHuhtala, you make a good point with the specialization to explicitly make the specialization, You just have to do it kindof funny private function template, specialization of that template. I'm going to put the example of what I'm talking about in an edit of the question. – IdeaHat Mar 19 '13 at 16:26

1 Answers1

1

I think I misunderstood your question when I put my earlier comment.

Assuming you can use c++11, or you can use boost, you could use something like !std::is_same< T1, null_type >::value /*or boost::is_same...*/ instead of typeid(T1) != typeid(null_type). This uses TMP to resolve to a compile-time constant, which most compilers would have no trouble optimizing away.

This is more of a question of how the C++ compiler handles const typeid calls.

I didn't answer this specific question, but if I understand what you were actually looking for, the above should suffice.

EHuhtala
  • 587
  • 3
  • 8
  • Not that `std::is_same` may be C++11, but it is also trivial to write in C++03. – Yakk - Adam Nevraumont Mar 19 '13 at 22:29
  • @EHuhtala, this does lead me to use the same code pattern over and over again...I quickly put together a macro i could use can you think of a less hacky way to do this? '#define RUNXONTYPE(x,t,num)\ {\ typedef t K;\ if (!std::is_same::value)\ {\ K*& img = (K*&)_buff[num];\ x;\ }\ } #define RUNXONALL(x)\ RUNXONTYPE(x,T0,0)\ RUNXONTYPE(x,T1,1)\ RUNXONTYPE(x,T2,2)\ RUNXONTYPE(x,T3,3)' – IdeaHat Mar 20 '13 at 14:30
  • An example of that macro in use: RUNXONALL(img=new K[max_size]) – IdeaHat Mar 20 '13 at 14:31
  • you could look at some variatic template foreach posts on this site. It would likely involve recursive templates and lambda functions, which is where I'm not so familiar. the following post might help if you're interested: http://stackoverflow.com/questions/12030538/c11-calling-a-function-for-each-variadic-template-argument-and-an-array – EHuhtala Mar 20 '13 at 15:13