CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Aug 2001
    Location
    Israel
    Posts
    101

    HELP! templates with a 'double' parameter

    Hi, try and run the following code. An explanation:
    I have two template classes for the test: D and I which are defined by 3 double/integer parameters.
    I've put a printf call in their ctor to see the parameter values.
    In main(), I try to create several objects of D and I. And as you will run this code, you'll see that each behaves really weird. For example:

    D<1,0,0>, D<-1,0,0> and D<2,0,0> give the same output: 1,1,1 , but D<3,0,0> gives the correct output: 3,0,0. If you change d1 to, say, D<5,0,0>, then d1,d2 and d3 will all give output: 5,0,0! It's as if d1..d3 are initialized with the same template instance, but d4 isn't!!! why!?!?!?

    D<20,0,0> and D<-20,0,0> give the same output: 20,0,0.
    The 'I' objects seem to be OK with any value.
    Anyway, look for yourselves. WHAT IS GOING ON HERE?

    And the weirdest one of all: try running it in the debugger, put a breakpoint on the 'printf' and as soon as you get there, take a look at the 'Context' combo box in VStudio. See what happens when you reach d4 and continue....

    Note: I even tried to work with 'float' instead of 'double', since it's only 32 bits (I thought it may have sth to do with it). No change.


    template <double x, double y, double z>
    class D
    {
    public: D() { printf("%f %f %f\n", x,y,z); }
    };

    template <int x, int y, int z>
    class I
    {
    public: I() { printf("%d %d %d\n", x,y,z); }
    };

    int main(int argc, char* argv[])
    {
    D<1.0,0,0> d1;
    D<-1.0,0,0> d2;
    D<2.0,0,0> d3;
    D<20.0,0,0> d4;
    D<(-20.0),0,0> d5;
    D<0,10,0> d6;
    D<0,-3.0,0> d7;
    D<0,-10.0,0> d8;

    I<1,0,0> i1;
    I<-1,0,0> i2;
    I<0,-10,0> i3;
    I<0,10,0> i4;

    return 0;
    }

  2. #2
    Join Date
    Sep 2002
    Posts
    1,747

    templates vs. the compiler

    I could probably be enticed to place money on the bet that you are using Microsoft's Visual C++. If this is truly the case, then check out Knowledge Base Article 240871. Although I haven't seen this problem pop up in exactly the form you have stated, it seems likely that what you are doing is another instance of this oft-bereaved problem with VC++'s name mangling / lookup methods...
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  3. #3
    Join Date
    Aug 2001
    Location
    Israel
    Posts
    101

    by the way...

    I've tried to compile with GNU, and it appears that it doesn't allow 'float' parameters.... so it's either a bug or a non-compliance issue (which should be documented if I ever find where!!!)

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449
    Template parameters defined as doubles is non-standard. Here it is from the ANSI/ISO specification, 14.1.4:
    A nontype template parameter shall have one of the following (optionally cv-qualified)
    types:
    integral or enumeration type,
    — pointer to object or pointer to function,
    — reference to object or reference to function,
    — pointer to member.
    So the code you posted is not even supposed to compile. Also, the template instantiation must have integral argument types. Therefore your instantiations are illegal also.

    Regards,

    Paul McKenzie

  5. #5
    Join Date
    Aug 2001
    Location
    Israel
    Posts
    101

    just as I thought...

    But it DID comile in VC++. That's exactly the problem (Their problem). But it's ok, I now know that it's a bug, since it doesn't compile under GNU.

  6. #6
    Join Date
    Sep 2002
    Posts
    1,747

    WRONG!!!!

    WRONGWRONGWRONGWRONGWRONG!!!

    I was wrong on this one. It was way too late for me and I missed entirely the real point. Paul is correct here. Its not a proper non-type parameter. Sorry for the misinfo... (glad I didn't have any money riding).
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  7. #7
    Join Date
    Oct 2001
    Location
    Kongsberg, Norway
    Posts
    18
    I can remember that I encountered the same problem in a small project last year. At that time I didn't know that template params defined as double was non-standard.

    My "solution" was to create a template called something like Tdouble:
    Code:
    template <int Q, int E>
    struct Tdouble
    {
    	static double value()
    	{
    		static const double val = pow(10.0, (double)E) * (double)Q;
    		return val;
    	}
    };
    This way I could use my original design with minimal changes. In your example you could then write something like this:
    Code:
    template <class X, class Y, class Z >
    struct D
    {
        D()
        {
            cout.precision(10);
            cout    << "x: " << X::value() << "\n"
                    << "y: " << Y::value() << "\n"
                    << "z: " << Z::value() << "\n"
                    << endl;
        }
    };
    
    typedef D< Tdouble<1,0>, Tdouble<0,0>, Tdouble<0, 0> >      d1;
    typedef D< Tdouble<-1,0>, Tdouble<0,0>, Tdouble<0, 0> >     d2;
    typedef D< Tdouble<2,0>, Tdouble<0,0>, Tdouble<0, 0> >      d3;
    typedef D< Tdouble<20,0>, Tdouble<0,0>, Tdouble<0, 0> >     d4;
    typedef D< Tdouble<-20,0>, Tdouble<0,0>, Tdouble<0, 0> >    d5;
    typedef D< Tdouble<0,0>, Tdouble<10,0>, Tdouble<0, 0> >     d6;
    typedef D< Tdouble<0,0>, Tdouble<-3,0>, Tdouble<0, 0> >     d7;
    typedef D< Tdouble<0,0>, Tdouble<-10,0>, Tdouble<0, 0> >    d8;
    
    
    int main()
    {
        d1 da;
        d2 db;
        d3 dc;
        d4 dd;
        d5 de;
        d6 df;
        d7 dg;
        d8 dh;
        
        cout << "---" << endl << endl;
        
        cout << Tdouble<123456789, -5>::value() << endl;    //1234.56789
        cout << Tdouble<1, -5>::value() << endl;            //0.00001
        cout << Tdouble<25,-2>::value() << endl;            //0.25
        
        system("pause");
    	return 0;
    }
    I know some may think this is not a nice solution, but it is at least an option that works in both VC and GNU.

    Comments are welcome

  8. #8
    Join Date
    Aug 2001
    Location
    Israel
    Posts
    101

    Well...

    There are a lot for ways to overcome the problem, but nm. I didn't want to use the E/Q technique, but I did figure out two optional ideas:

    1. implement IEEE754SP (floating point) on a 32 integer within the class, so I'm not limited with any compiler moods :-)

    2. use the integer as a fixed-point variable (you know, Lword is the fraction, Hword is the integer, and so on). Much faster.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured