Template function parameters

Started by
8 comments, last by Antheus 14 years, 11 months ago
I have run across an issue where I have a template matrix class, and would like to pass this to a function without having to templatize the function. Here is an example
    template <unsigned S, typename T>
    struct Matrix {
    
        T mat ;
        
        <span class="cpp-keyword">unsigned</span> dim ;
        
        Matrix() : dim(S) {}
        
        T&amp; <span class="cpp-keyword">operator</span>()(<span class="cpp-keyword">unsigned</span> i, <span class="cpp-keyword">unsigned</span> j) { <span class="cpp-keyword">return</span> mat<span style="font-weight:bold;">[j] ; }
    };
    

    <span class="cpp-keyword">void</span> invert(Matrix&amp; m) {}

</pre></div><!–ENDSCRIPT–>

Essentially i am looking to pass a matrix to a function as if it were a standard class. However, I must make the function a template so I can inform the compiler of the type of matrix I am sending. My assumption is by doing this the code will be duplicated for each type of matrix I send it. This could possible cause quite a bit of code bloat. 

I see I could simply move the invert function into the matrix class. But I still believe for each matrix type the code would still be duplicated. 

Is there anyway to accomplish what I am trying to do?
∫Mc
Advertisement
How would you know the dimensions of the Matrix inside of invert when it's not a template?

And how many different sizes do you really need?

The dim member variable. And yes I do not need that many sizes. For my particular project I only need a 4x4. I just wanted to know if this was possible.
∫Mc
You can create a base class with virtual functions that your Matrix class inherits from and then have functions use that.
Quote:Original post by smc

I see I could simply move the invert function into the matrix class. But I still believe for each matrix type the code would still be duplicated.


Templates are compile-time polymorphism, achieved through code generation for each instantiation. Each results in unique class with unique code path, completely unrelated to other instantiations of same template.

If this is not an option, matrix cannot be parametrized by S, and that parameter needs to be passed as regular value, and 'mat' allocated dynamically during run-time.

Quote:This could possible cause quite a bit of code bloat.
Templates *are* bloat. Today's compilers have gotten really good at effectively eliminating it as a serious problem, but template instantiations result in more of similar, yet not duplicated, code.
I suppose the actual work can be done by a function that doesn't need the size parameter.

namespace detail {template <class T>void invert(T* matrix_data, unsigned size){    //work here}}template <class T, unsigned S>void invert(Matrix<T, S>& m){    detail::invert(&m.mat[0][0], S);}
Quote:Original post by visitor
I suppose the actual work can be done by a function that doesn't need the size parameter.

*** Source Snippet Removed ***


That still results in one instantiation of Matrix for each parameter pair, and one instance of invert.

Meanwhile, the only performance sensitive part - the calculation itself, will use non-constant values, which might (profiling!) result in slower run-time. The primary benefit of templated Matrix (unrolling, hard-coding of stack-allocated array or pre-calculating during compile time for compile-time known dimensions) will be lost. But since compiler will likely know that S is constant, it will probably inline entire //work into invert(), which will result in same outcome as if invert() were templated directly, the code is just less clear.

Profiling is required either way. But experience has shown that simply hard-coding some well-known matrices works in many cases, or generic, run-time constructed matrices are required anyway.

And code duplication in this case isn't necessarily problematic, even for larger numbers of matrices.

SiCrane; This is a great solution. I will definitely have to play around with this approach. Come to think of it using templates types at the higher levels of inheritance is a nice way to create specialized types while keeping the majority of the code abstracted away from the specializations (in other words keeping it clean from type specifiers). I am not sure why I have not thought of this before. I really need to start playing around with the language.

Are there any good books/sites on class design patterns?

visitor; This is another possibility. It certainly would cut down on the code duplication size.


Thanks for the food.
∫Mc
Original post by Antheus
Quote:Original post by visitor

Meanwhile, the only performance sensitive part - the calculation itself, will use non-constant values, which might (profiling!) result in slower run-time. The primary benefit of templated Matrix (unrolling, hard-coding of stack-allocated array or pre-calculating during compile time for compile-time known dimensions) will be lost. But since compiler will likely know that S is constant, it will probably inline entire //work into invert(), which will result in same outcome as if invert() were templated directly, the code is just less clear.



This is interesting. I never considered using templates for performance optimizations. It definitely makes sense that the compiler could perform some serious optimizations on the code given the right information.

I just got knocked down to noob level again. I am glad I have the summer to work on some no deadline personal projects.
∫Mc
Quote:Original post by smc

This is interesting. I never considered using templates for performance optimizations. It definitely makes sense that the compiler could perform some serious optimizations on the code given the right information.


Well, you talked about code bloat, which is a compiler implementation detail, not a language issue, so I assumed other aspects matter too.

One of main reasons why code bloat is a problem (100Mb executable might be unwieldy, but is not problematic in itself, and would probably compress quite well) is the instruction cache problems, which usually results in slower running code, even though the operations are somewhat simpler. Even when compared to identical non-templated code, simply higher use of memory will cause slowdowns.

But as far as C++ language is concerned, code bloat is not really a factor, that is merely a practical consideration, for either performance, deployment or platform reasons.

I was once toying around with some template magic, and write a templated class that would generate instances for all 32-bit values. The resulting executable was several megabytes (I have no clue why it wasn't 16 gig, perhaps many ranges weren't used), and compilation took a minute or so (MVC2008), but it worked. It isn't something to do, I merely wanted to see if compiler could chew over this.

I think I was trying to parse user input into templated class using recursive parsing of digits, so that final template was result of multiple intermediate templates, but final version really did support entire 32-bit range.

This topic is closed to new replies.

Advertisement