template question

Discussion in 'C++' started by graham, Nov 29, 2011.

  1. graham

    graham Guest

    Hi,

    can anybody please explain why the following prints 4, 3, 2, 1, 0 and
    not 0, 1, 2, 3, 4

    I like what this does but don't understand why the values are assigned
    the values in the order they are?

    cheers

    Graham

    class type2intbase {
    template <typename T>
    friend struct type2int;

    static const int next() {
    static int id = 0; return id++;
    }
    };

    template <typename T>
    struct type2int {
    static const int value() {
    static const int id = type2intbase::next(); return id;
    }
    };


    struct foo{};
    struct foo1{};
    struct foo2{};
    struct foo3{};
    struct foo4{};

    #include <iostream>
    using namespace std;

    int main(int argc, char** argv)
    {

    type2int<foo> zero;
    type2int<foo1> one;
    type2int<foo2> two;
    type2int<foo3> three;
    type2int<foo4> four;

    cout << zero.value() << " " << one.value() << " " << two.value()
    << " " << three.value() << " " << four.value() << " " << endl;
    return 0;
    }
     
    graham, Nov 29, 2011
    #1
    1. Advertising

  2. graham <> wrote:
    > can anybody please explain why the following prints 4, 3, 2, 1, 0 and
    > not 0, 1, 2, 3, 4


    > cout << zero.value() << " " << one.value() << " " << two.value()
    > << " " << three.value() << " " << four.value() << " " << endl;


    Because that's equivalent to:

    operator<<(operator<<(operator<<(operator<<(cout, four.value()), three.value()), two.value()), one.value());
     
    Juha Nieminen, Nov 29, 2011
    #2
    1. Advertising

  3. graham

    graham Guest

    On Nov 29, 10:53 am, Juha Nieminen <> wrote:
    > graham <> wrote:
    > > can anybody please explain why the following prints 4, 3, 2, 1, 0 and
    > > not 0, 1, 2, 3, 4
    > >   cout << zero.value() <<  " " << one.value() << " " << two.value()
    > > << " " << three.value() << " " << four.value() << " " << endl;

    >
    >   Because that's equivalent to:
    >
    > operator<<(operator<<(operator<<(operator<<(cout, four.value()), three.value()), two.value()), one.value());


    Fair enoughski, but I'd like to know how the values are assigned. If I
    do this with the above code;

    cout << zero.value() << " " << one.value() << " " << four.value() <<
    " " << endl;

    I get

    2 1 0

    "zero" is now 2
    "one" is now 1
    "four" is still 0

    I'd like to know the why, there's something going on behind the scenes
    I'm not gettin'

    Cheers

    GrahamO
     
    graham, Nov 29, 2011
    #3
  4. On 11/29/2011 10:24 AM, graham wrote:
    [...]
    > cout << zero.value() << " " << one.value() << " " << two.value()
    > << " " << three.value() << " " << four.value() << " " << endl;


    according to to standard it is unspecified in which order will the
    arguments of the calls be evaluated. to make things simpler - having:
    void f(int,int);
    code:
    f( one.value(), two.value() )
    can call:
    f(0, 1)
    as well as
    f(1, 0)
    in general you can get any permutation of evaluation order. it depends
    on the compiler. performing calls left-to-right or right-to-left is
    easiest, thus most often used by vendors. and so your code, may
    accidentally work on some compilers versions.

    for example your code gives 4 3 2 1 0 on gcc and 0 1 2 3 4 on clang.
    both of them are fine, since you cannot depend on evaluation order in
    this case.

    if your calls have side effects, first compute values, in required
    order, and then pass it as arguments.

    --
    pozdrawiam serdecznie / best regards,
    Bartek 'BaSz' Szurgot

    http://www.baszerr.org
     
    bartek szurgot, Nov 29, 2011
    #4
  5. graham

    graham Guest

    On Nov 29, 11:40 am, bartek szurgot <> wrote:
    > On 11/29/2011 10:24 AM, graham wrote:
    > [...]
    >
    > >    cout << zero.value() <<  " " << one.value() << " " << two.value()
    > > << " " << three.value() << " " << four.value() << " " << endl;

    >
    > according to to standard it is unspecified in which order will the
    > arguments of the calls be evaluated. to make things simpler - having:
    > void f(int,int);
    > code:
    > f( one.value(), two.value() )
    > can call:
    > f(0, 1)
    > as well as
    > f(1, 0)
    > in general you can get any permutation of evaluation order. it depends
    > on the compiler. performing calls left-to-right or right-to-left is
    > easiest, thus most often used by vendors. and so your code, may
    > accidentally work on some compilers versions.
    >
    > for example your code gives 4 3 2 1 0 on gcc and 0 1 2 3 4 on clang.
    > both of them are fine, since you cannot depend on evaluation order in
    > this case.
    >
    > if your calls have side effects, first compute values, in required
    > order, and then pass it as arguments.
    >
    > --
    > pozdrawiam serdecznie / best regards,
    > Bartek 'BaSz' Szurgot
    >
    > http://www.baszerr.org


    Awesome! Thanks a million, thats the reply I was looking for.

    This;


    type2int<foo> zero;
    int a = zero.value();
    type2int<foo1> one;
    int b = one.value();
    type2int<foo2> two;
    int c = two.value();
    type2int<foo3> three;
    int d = three.value();
    type2int<foo4> four;
    int e = four.value();

    cout << a << " " << b << " " << c << " " << d << " " << e << endl;
    cout << zero.value() << " " << one.value() << " " << four.value() <<
    " " << endl;

    outputs;

    0 1 2 3 4
    0 1 4

    Which is what I wanted.

    thanks a million Bartek, have a nice day

    Graham
     
    graham, Nov 29, 2011
    #5
  6. bartek szurgot <> wrote:
    > if your calls have side effects, first compute values, in required
    > order, and then pass it as arguments.


    The easier solution is to simply split the std::cout call:

    std::cout << zero.value() << " ";
    std::cout << one.value() << " ";
    std::cout << two.value() << " ";
    std::cout << three.value() << " ";
    std::cout << four.value() << std::endl;

    The moral of the story is that you should never use functions that have
    side effects as several parameters to another function (taking more than
    one parameter).
     
    Juha Nieminen, Nov 29, 2011
    #6
  7. graham <> wrote:
    > type2int<foo> zero;
    > int a = zero.value();
    > type2int<foo1> one;
    > int b = one.value();
    > type2int<foo2> two;
    > int c = two.value();
    > type2int<foo3> three;
    > int d = three.value();
    > type2int<foo4> four;
    > int e = four.value();
    >
    > cout << a << " " << b << " " << c << " " << d << " " << e << endl;
    > cout << zero.value() << " " << one.value() << " " << four.value() <<
    > " " << endl;


    As I said in my other post, that's the hard way of doing it. Just do it
    like this:

    std::cout << zero.value() << " ";
    std::cout << one.value() << " ";
    std::cout << two.value() << " ";
    std::cout << three.value() << " ";
    std::cout << four.value() << std::endl;
     
    Juha Nieminen, Nov 29, 2011
    #7
  8. graham

    graham Guest

    On Nov 29, 12:04 pm, Juha Nieminen <> wrote:
    > graham <> wrote:
    > > type2int<foo> zero;
    > > int a = zero.value();
    > > type2int<foo1> one;
    > > int b = one.value();
    > > type2int<foo2> two;
    > > int c = two.value();
    > > type2int<foo3> three;
    > > int d = three.value();
    > > type2int<foo4> four;
    > > int e = four.value();

    >
    > > cout << a <<  " " << b << " " << c << " " << d << " " << e << endl;
    > > cout << zero.value() <<  " " << one.value() << " " << four.value() <<
    > > " " << endl;

    >
    >   As I said in my other post, that's the hard way of doing it. Just do it
    > like this:
    >
    > std::cout << zero.value() << " ";
    > std::cout << one.value() << " ";
    > std::cout << two.value() << " ";
    > std::cout << three.value() << " ";
    > std::cout << four.value() << std::endl;


    thanks but Bartek hit the nail on the head. His explanation was spot
    on. Thanks anyways

    have a nice day.

    G
     
    graham, Nov 29, 2011
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Theis
    Replies:
    2
    Views:
    495
    Chris Theis
    Jul 24, 2003
  2. tom_usenet
    Replies:
    0
    Views:
    560
    tom_usenet
    Jul 24, 2003
  3. Replies:
    1
    Views:
    2,142
    Gianni Mariani
    Jun 8, 2007
  4. Peng Yu
    Replies:
    3
    Views:
    802
    Thomas J. Gritzan
    Oct 26, 2008
  5. nguillot
    Replies:
    5
    Views:
    551
Loading...

Share This Page