KDE

NAVIGATION
CATEGORIES
REFERRENCE
LINKS
  • questions about c++ templates

    9 answers - 1847 bytes - related search similar search Add To My Delicious Add To My Stumble Upon Add To My Google Mark Add To My Facebook Add To My Digg Add To My Reddit

    Friday 18 August 2006 09:11, B Jacob wrote:
    Hi!
    I've got a few questions, so if you can help me that'll result in a better
    kdesupport/eigen library ;)
    1. when you instantiate a template class, does the compiler generate code
    only for those methods that are getting called for this particular template
    instantiation, or does it generate code for all methods?
    Concretely:
    template<class Tclass M
    {
    // 500 methods that DN'T call one another
    void method1();
    void method500();
    };
    M<intm;
    m.method1();
    does that generate code for the 499 unused methods of M<int?
    No. (Although it may be compiler dependent; a recent version of g++ does it
    right)
    2. when you instantiate the same template class for various pointer types,
    does the compiler generate code only once ?
    Concretely:
    M<int *mi;
    M<SomeClass *mc; // does that generate code for M<SomeClass *or does
    // that share code with M<int *?
    No.
    3. In my code, I have a class A (it's an assignable data type) and it would
    be natural for me at some point to do
    QList<Al;
    and then to use only a few elementary methods of QList<A(like append
    elements and do a foreach). How much binary size would be replaced by doing
    QList<A *l;
    That would be less convenient for me, so I'd like to know if it's worth it.
    The difference would be n * sizeof(A) - n * sizeof(A*) where n is the number
    of elements in your list. The size of the generated template methods would
    not change (although stack allocations within the generated template methods
    would have a different size and the first version may call constructors,
    while the second version would not).
    Hope that helps.
  • No.1 | | 799 bytes | |

    Friday 18 August 2006 09:52, B Jacob wrote:
    hey, thanks a lot for your answers. question though:
    M<SomeClass *mc; // does that generate code for M<SomeClass *or
    does // that share code with M<int *?

    No.

    when you answer "No" here, does it mean, "No, it doesn't generate code for
    M<SomeClass *>", or does it mean, "No, it doesn't share code with M<int *>"
    ?

    If it doesn't share code, do you have a clue why ? At first sight, one
    would think that from a low-level point of view, all pointer types are
    equivalent (to, say, void*) and thus there shouldn't be any difference
    between M<some_type *and M<some_other_type *>, so code could be shared
    ?

    Sorry, that was unclear. No it does not share code.
  • No.2 | | 2302 bytes | |

    Friday 18 August 2006 09:52, B Jacob wrote:
    hey, thanks a lot for your answers. question though:
    M<SomeClass *mc; // does that generate code for M<SomeClass *or
    does // that share code with M<int *?

    No.

    when you answer "No" here, does it mean, "No, it doesn't generate code for
    M<SomeClass *>", or does it mean, "No, it doesn't share code with M<int *>"
    ?

    If it doesn't share code, do you have a clue why ? At first sight, one
    would think that from a low-level point of view, all pointer types are
    equivalent (to, say, void*) and thus there shouldn't be any difference
    between M<some_type *and M<some_other_type *>, so code could be shared
    ?

    Grrr, hit the send button too early.

    It can't share code, because you could have the following:

    template<typename T>
    void f(T t)
    {
    t->g();
    }

    Where some_type may have g(), but some_other_type may not. , in a more
    complicated situtation, they may both have g(), and both g()s are declared
    virtual, but each g() lives in different spots in the vtable, so the same
    calling code would end up calling different methods if the offset into the
    vtable was the same because they were running the same generated code.

    Now if you can guarantee none of the above situations are going to happen (ie
    two classes with identical definitions), then I suppose you _could_ merge the
    two. I'm not sure what the standard says. However, that's a fair bit of
    work for the compiler for what's likely a rare situation. g++ does not do
    it.

    Here's a test program to confirm:
    #include <iostream>

    using namespace std;

    class T1
    {
    public:
    void g() { cout << "T1" << endl; }
    };

    class T2
    {
    public:
    void g() { cout << "T2" << endl; }
    };

    template<typename T>
    void f(T t)
    {
    t->g();
    }

    int main()
    {
    T1 t1;
    T2 t2;

    f(&t1);
    f(&t2);

    return 0;
    }

    10:02:38 [9]; nm -C ./a.out| grep 'void f'
    08048708 W void f<T1*>(T1*)
    08048748 W void f<T2*>(T2*)

    Note that the two f()'s have different addresses.
  • No.3 | | 1557 bytes | |

    Friday 18 August 2006 16:32, Craig Howard wrote:
    Friday 18 August 2006 09:11, B Jacob wrote:
    Hi!

    I've got a few questions, so if you can help me that'll result in a
    better kdesupport/eigen library ;)

    1. when you instantiate a template class, does the compiler generate code
    only for those methods that are getting called for this particular
    template instantiation, or does it generate code for all methods?

    Concretely:

    template<class Tclass M
    {
    // 500 methods that DN'T call one another
    void method1();

    void method500();
    };

    M<intm;
    m.method1();

    does that generate code for the 499 unused methods of M<int?

    No. (Although it may be compiler dependent; a recent version of g++ does
    it right)

    However, I think the picture changes a bit when a template contains virtual
    functions. For example, that a template class inherits from a class that has
    pure virtual functions which the template, when instantiated, implements.

    In that case I believe it must expand all functions. But of course, dead code
    elimination optimizations can potentially see that it's not needed, as for
    any other case.

    reason I like templates much is exactly that only the code one needs is
    actually used. can write a complex class that accounts for much and is
    convenient, but only what is actually needed is expanded.

    Cheers,

    Frans

    >Visit #unsub to unsubscribe <<
  • No.4 | | 1621 bytes | |

    Friday 18 August 2006 11:03, Frans Englich wrote:
    However, I think the picture changes a bit when a template contains virtual
    functions. For example, that a template class inherits from a class that
    has pure virtual functions which the template, when instantiated,
    implements.

    In that case I believe it must expand all functions. But of course, dead
    code elimination optimizations can potentially see that it's not needed, as
    for any other case.

    reason I like templates much is exactly that only the code one needs is
    actually used. can write a complex class that accounts for much and is
    convenient, but only what is actually needed is expanded.

    Interesting. You are correct:

    #include <iostream>

    using namespace std;

    class Base
    {
    public:
    virtual ~Base() {}

    virtual void pure() = 0;
    };

    template<typename T>
    class Child : public Base
    {
    public:
    virtual ~Child() {}

    virtual void pure() {}
    void g() { cout << "T1" << endl; }
    };

    int main()
    {
    Child<intc;

    c.g();

    return 0;
    }

    12:11:38 [21]; nm -C ./a.out | grep Child
    080489ba W Child<int>::g()
    080488de W Child<int>::pure()
    080488c0 W Child<int>::Child()
    0804890a W Child<int>::~Child()
    08048988 W Child<int>::~Child()
    08048b14 V typeinfo for Child<int>
    08048b20 V typeinfo name for Child<int>
    08048b00 V vtable for Child<int>

    Does anybody know why that is? And why there are two destructors for Child?
  • No.5 | | 1681 bytes | |

    Well, with this code, templates have no influence, at least for nm: with or
    without them, there is no difference except for addresses.
    -0804894a W Base::Base()
    +080489ee W Base::Base()
    08048920 W Base::~Base()
    080488f6 W Base::~Base()
    080488cc W Base::~Base()
    -080489ec W Child<int>::g()
    -08048a1a W Child<int>::pure()
    -0804895a W Child<int>::Child()
    -080489b4 W Child<int>::~Child()
    -0804897c W Child<int>::~Child()
    +080489c0 W Child::g()
    +080489ba W Child::pure()
    +080489fe W Child::Child()
    +08048982 W Child::~Child()
    +0804894a W Child::~Child()

    Regards,

    Kleag
    Le vendredi 18 2006 21:13, Craig Howard a *:
    Friday 18 August 2006 11:03, Frans Englich wrote:
    Interesting. You are correct:

    #include <iostream>

    using namespace std;

    class Base
    {
    public:
    virtual ~Base() {}

    virtual void pure() = 0;
    };

    template<typename T>
    class Child : public Base
    {
    public:
    virtual ~Child() {}

    virtual void pure() {}
    void g() { cout << "T1" << endl; }
    };

    int main()
    {
    Child<intc;

    c.g();

    return 0;
    }
    --
    12:11:38 [21]; nm -C ./a.out | grep Child
    080489ba W Child<int>::g()
    080488de W Child<int>::pure()
    080488c0 W Child<int>::Child()
    0804890a W Child<int>::~Child()
    08048988 W Child<int>::~Child()
    08048b14 V typeinfo for Child<int>
    08048b20 V typeinfo name for Child<int>
    08048b00 V vtable for Child<int>

    Does anybody know why that is? And why there are two destructors for
    Child?
  • No.6 | | 1874 bytes | |

    Friday 18 August 2006 14:09, Kleag wrote:
    Well, with this code, templates have no influence, at least for nm: with or
    without them, there is no difference except for addresses.

    Right, but that's significant, because Child::pure() wasn't referenced, so it
    shouldn't have been created. so I thought.
    -0804894a W Base::Base()
    +080489ee W Base::Base()
    08048920 W Base::~Base()
    080488f6 W Base::~Base()
    080488cc W Base::~Base()
    -080489ec W Child<int>::g()
    -08048a1a W Child<int>::pure()
    -0804895a W Child<int>::Child()
    -080489b4 W Child<int>::~Child()
    -0804897c W Child<int>::~Child()
    +080489c0 W Child::g()
    +080489ba W Child::pure()
    +080489fe W Child::Child()
    +08048982 W Child::~Child()
    +0804894a W Child::~Child()

    Regards,

    Kleag

    Le vendredi 18 2006 21:13, Craig Howard a *:
    Friday 18 August 2006 11:03, Frans Englich wrote:
    Interesting. You are correct:

    #include <iostream>

    using namespace std;

    class Base
    {
    public:
    virtual ~Base() {}

    virtual void pure() = 0;
    };

    template<typename T>
    class Child : public Base
    {
    public:
    virtual ~Child() {}

    virtual void pure() {}
    void g() { cout << "T1" << endl; }
    };

    int main()
    {
    Child<intc;

    c.g();

    return 0;
    }
    --
    12:11:38 [21]; nm -C ./a.out | grep Child
    080489ba W Child<int>::g()
    080488de W Child<int>::pure()
    080488c0 W Child<int>::Child()
    0804890a W Child<int>::~Child()
    08048988 W Child<int>::~Child()
    08048b14 V typeinfo for Child<int>
    08048b20 V typeinfo name for Child<int>
    08048b00 V vtable for Child<int>

    Does anybody know why that is? And why there are two destructors for
    Child?
  • No.7 | | 2542 bytes | |

    Craig Howard (a):
    Friday 18 August 2006 09:11, Bt Jacob wrote:
    >Hi!
    >>

    >I've got a few questions, so if you can help me that'll result in a better
    >kdesupport/eigen library ;)
    >>

    >1. when you instantiate a template class, does the compiler generate code
    >only for those methods that are getting called for this particular template
    >instantiation, or does it generate code for all methods?
    >>

    >Concretely:
    >>

    >
    >template<class Tclass M
    >{
    >// 500 methods that DN'T call one another
    >void method1();
    >
    >void method500();
    >};
    >>

    >
    >>

    >M<intm;
    >m.method1();
    >
    >>

    >does that generate code for the 499 unused methods of M<int?


    No. (Although it may be compiler dependent; a recent version of g++ does it
    right)

    Well, it depends how instantiation is done.
    If you put the code in header file and any user of header can
    instantiate the code, then I guess unnecessary methods are not
    generated. But if you create a library (which I assume is what will be
    done for eigen library) and you do explicit instantiation for some
    types, then:

    $ cat a.h
    template<class T>
    class M
    {
    public:
    // 500 methods that DN'T call one another
    void method1();
    void method2();
    void method500();
    };

    $ cat a.cpp
    #include <iostream>
    #include "a.h"

    using namespace std;

    template <class T>
    void M<T>::method1()
    {
    }

    template <class T>
    void M<T>::method2()
    {
    }

    template <class T>
    void M<T>::method500()
    {
    }

    template class M<int>;

    Then:
    $ g++ -c a.cpp -o a.o
    $ g++ -shared a.o -o a.so
    $ nm -C ./a.so | grep method
    000006d6 W M<int>::method1()
    000006dc W M<int>::method2()
    000006e2 W M<int>::method500()

    HTH

    Krzysztof Lichota


    >Visit #unsub to unsubscribe <<


    PGP SIGNATURE
    Version: GnuPG v1.4.2.2 (GNU/Linux)
    Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

    TTYX88BaV+GFNIf5oBJ0k=
    =+4ko
    PGP SIGNATURE
  • No.8 | | 618 bytes | |

    Le samedi 19 2006 04:12, Craig Howard a *:
    Friday 18 August 2006 14:09, Kleag wrote:
    Well, with this code, templates have no influence, at least for nm: with
    or without them, there is no difference except for addresses.

    Right, but that's significant, because Child::pure() wasn't referenced, so
    it shouldn't have been created. so I thought.

    Sorry, I missed the point. Interestingly, recompiling the template version
    with , references to g() are removed from the nm output while pure() is
    still present. Also the number of constructors and destructors change.

    Kleag
  • No.9 | | 297 bytes | |

    Craig Howard wrote:
    [] And why there are two destructors for
    Child?
    The reason is briefly explained in this document,
    Have a look at section 2.1.3 "Constructors and Destructors" on page 7.

    >Visit #unsub to unsubscribe <<

Re: questions about c++ templates


max 4000 letters.
Your nickname that display:
In order to stop the spam: 3 + 2 =
QUESTION ON "KDE"

EMSDN.COM