dependent template parameter?

S

stephen.diverdi

Any suggestions on how to accomplish something like this doScale
function?

#include <stdio.h>

template < typename T, T scale >
T doScale ( const T &x )
{
return ( x * scale );
}

int main ()
{
float x = 1;
float y = doScale< float, 2.0f >( x );
printf( "%f %f\n", x, y );

int a = 1;
int b = doScale< int, 3 >( a );
printf( "%d %d\n", a, b );

return 0;
}

I want to have the second template parameter be a constant of a type
that is determined by the first template parameter. g++ and comeau
both reject it. If you're curious, I'm looking to replace a run-time
constant with a compile-time constant in some critical code. Thanks,

-stephen diverdi
(e-mail address removed)
 
V

Victor Bazarov

Any suggestions on how to accomplish something like this doScale
function?

#include <stdio.h>

template < typename T, T scale >
T doScale ( const T &x )
{
return ( x * scale );
}

int main ()
{
float x = 1;
float y = doScale< float, 2.0f >( x );
printf( "%f %f\n", x, y );

int a = 1;
int b = doScale< int, 3 >( a );
printf( "%d %d\n", a, b );

return 0;
}

I want to have the second template parameter be a constant of a type
that is determined by the first template parameter. g++ and comeau
both reject it. If you're curious, I'm looking to replace a run-time
constant with a compile-time constant in some critical code. Thanks,

You can't have 'float' as the type of the non-type template argument.
You're SOL in this matter. Pass the scale by value. The compiler will
optimize it for you.

V
 
S

sdiverdi

You can't have 'float' as the type of the non-type template argument.
You're SOL in this matter.  Pass the scale by value.  The compiler will
optimize it for you.
Hmm, too bad. Thanks!

-stephen diverdi
(e-mail address removed)
 
D

dix75

Hmm, too bad.  Thanks!

-stephen diverdi
(e-mail address removed)

Try so

template < typename T>
T doScale ( const T &x, double scale)
{
return ( x * scale );

}

int main ()
{
float x = 1;
float y = doScale( x, 2.0f );
printf( "%f %f\n", x, y );

int a = 1;
int b = doScale( a, 3 );
printf( "%d %d\n", a, b );

return 0;

}
 
D

dix75

Hmm, too bad.  Thanks!

-stephen diverdi
(e-mail address removed)

Try so


template < typename T>
T doScale ( const T &x, double scale)
{
return ( x * scale );

}

int main ()
{
float x = 1;
float y = doScale( x, 2.0f );
printf( "%f %f\n", x, y );

int a = 1;
int b = doScale( a, 3 );
printf( "%d %d\n", a, b );

return 0;

}
 
S

Scooser

Hi Stephen,
I'm not sure if this helps you, but as far as I understand you, your
idea ist to replace a "float y = CONST_XYZ * x;" with something like
this "float y = doScale<float, CONST_XYZ>(x)". Hoping that the
compiler can do better with the template right?

This is possible but to make it work you have to add a layer of
template indirection. For example you can do it like this

#include <stdio.h>

namespace Constant
{
enum const_id
{
ONE,
TWO
};

namespace {

template<typename T, const_id id> class CScaler;
template<>
struct CScaler<float, ONE>
{
float operator () (const float& value) const
{ return 2.0f * value; }
};

template<>
struct CScaler<int, TWO>
{
int operator () (const int& value) const
{ return 3 * value; }
};
}

template<const_id id, typename T>
inline T scale (const T& value)
{
CScaler<T,id> scaler;
return scaler(value);
}
}

int main(void)
{
printf ("Test");

float x = 1.0f;
float y = Constant::scale<Constant::ONE>( x );
printf( "%f %f\n", x, y );

int a = 1;
int b = Constant::scale<Constant::TWO>( a );
printf( "%d %d\n", a, b );

return 0;
}


But in general I don't see the benefit because the compiler should be
able to optimize the "runtime" constants away as long as they are
known on compile time which is required to make the template approach
work.
 
N

Noah Roberts

Hmm, too bad. Thanks!

There is, however, an alternative.

If you look in the boost::units library you'll find a "static_rational"
class. It is meant to address this problem for you and is mostly
algebraicly complete (there are some impossible operators that were not
implemented). Or you can implement your own fairly easily if you don't
need all that:

template < int Num, int Denom >
struct rational
{
static double value() { return static_cast<double>(Num)/Denom; }
};

Now your code:

template < typename T, typename Scale >
T doScale(T const& x)
{
return static_cast<T>(x * Scale::value());
}
 
S

sdiverdi

Try so

template < typename T>
T doScale ( const T &x, double scale)
{
        return ( x * scale );

}

int main ()
{
        float x = 1;
        float y = doScale( x, 2.0f );
        printf( "%f %f\n", x, y );

        int a = 1;
        int b = doScale( a, 3 );
        printf( "%d %d\n", a, b );

        return 0;

}

Ah, thanks but that's what I have already. I was hoping to avoid the
run-time variable for scale, as I always pass a compile-time constant
in there, in the interest of trying to optimize an inner loop.

-stephen diverdi
(e-mail address removed)
 
S

sdiverdi

    template<typename T, const_id id> class CScaler;
    template<>
    struct CScaler<float, ONE>
    {
      float operator () (const float& value) const
      { return 2.0f * value; }
    };

    template<>
    struct CScaler<int, TWO>
    {
      int operator () (const int& value) const
      { return 3 * value; }
    };

Interesting idea, but since this will require multiple complete
implementations of the doScale function, each with the different
compile-time constants hard-wired in, it doesn't gain me anything over
just writing multiple functions.
But in general I don't see the benefit because the compiler should be
able to optimize the "runtime" constants away as long as they are
known on compile time which is required to make the template approach
work.

It should, but what I have is a large-ish function that uses some
constants that differ for char vs. short vs. float versions for some
heavy calculations. Looking at the assembly, I can see that a
variable is getting passed around, rather than a constant. So I was
looking for a way to force the compiler's hand.

Thanks,

-stephen diverdi
(e-mail address removed)
 
S

sdiverdi

template < int Num, int Denom >
struct rational
{
  static double value() { return static_cast<double>(Num)/Denom; }

};

Ah, of course! I guess my template-fu is still a bit weak, as these
(ab)uses of the type system often don't occur to me. I'll give it a
try and see what the compiler can do with it. Thanks!

-stephen diverdi
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,260
Messages
2,571,038
Members
48,768
Latest member
first4landlord

Latest Threads

Top