context in template point of instantiation (g++)

Discussion in 'C++' started by carlos.urena.almagro@gmail.com, Jan 16, 2007.

  1. Guest

    Hello,


    I'm sorry if this post raises a question with obvious answer, or if it
    has been already posted and solved. I was wondering about how the
    compiler (in my case, gcc 4.0.2 on linux) handles templates
    instantation, and what the standard says about that. I created a
    "difficult" case, in which the meaning of a call to a function (which
    is dependant) depends on the context where a template is instantiated.
    I have three compilation units and a header with a template, and, to my
    surprise, the output depends on....the order in which compilation units
    are compiled and linked ! --- I have two overloaded versions of 'f' in
    two compilation units, but the compiler issues calls to either one
    depending on the order of compilation or linking. It is correct w.r.t
    the standard ? it is a bug in gcc ? -- I think this is related with the
    mecanism for creating single template instantiation, which can be donde
    at link time, but I'm not sure about the details.

    'make' creates two binaries 'a1' and 'a2', with different output, but
    'a1' and 'a2' are equal except for the order compilation units are
    given to 'g++'. I've included the files in the text (including
    makefile)

    Thanks a lot in advance for any answers,
    Carlos.

    file t.H
    ---------
    template<typename T> T Applyf( T a )
    { return f(a) ; }


    file t1.C
    -----------
    #include <iostream>
    #include "t.H"

    using namespace std ;

    double f( double x )
    {
    return x*x ;
    }

    void g1()
    {
    cout << Applyf(1.0) << endl ;
    }

    file t2.C
    -----------
    #include <iostream>
    #include "t.H"

    using namespace std ;

    double f( float x )
    {
    return x+x ;
    }

    void g2()
    {
    cout << Applyf(1.0) << endl ;
    }

    file tmain.C
    -----------------

    void g1() ;
    void g2() ;

    int main( int argc, char * argv[] )
    {
    g1() ;
    g2();
    }


    file makefile:
    ------------------
    x: a1 a2
    ./a1
    ./a2
    a1:
    g++ -o a1 t1.C t2.C tmain.C

    a2:
    g++ -o a2 t2.C t1.C tmain.C
    , Jan 16, 2007
    #1
    1. Advertising

  2. Ondra Holub Guest

    napsal:
    > Hello,
    >
    >
    > I'm sorry if this post raises a question with obvious answer, or if it
    > has been already posted and solved. I was wondering about how the
    > compiler (in my case, gcc 4.0.2 on linux) handles templates
    > instantation, and what the standard says about that. I created a
    > "difficult" case, in which the meaning of a call to a function (which
    > is dependant) depends on the context where a template is instantiated.
    > I have three compilation units and a header with a template, and, to my
    > surprise, the output depends on....the order in which compilation units
    > are compiled and linked ! --- I have two overloaded versions of 'f' in
    > two compilation units, but the compiler issues calls to either one
    > depending on the order of compilation or linking. It is correct w.r.t
    > the standard ? it is a bug in gcc ? -- I think this is related with the
    > mecanism for creating single template instantiation, which can be donde
    > at link time, but I'm not sure about the details.
    >
    > 'make' creates two binaries 'a1' and 'a2', with different output, but
    > 'a1' and 'a2' are equal except for the order compilation units are
    > given to 'g++'. I've included the files in the text (including
    > makefile)
    >
    > Thanks a lot in advance for any answers,
    > Carlos.
    >
    > file t.H
    > ---------
    > template<typename T> T Applyf( T a )
    > { return f(a) ; }
    >
    >
    > file t1.C
    > -----------
    > #include <iostream>
    > #include "t.H"
    >
    > using namespace std ;
    >
    > double f( double x )
    > {
    > return x*x ;
    > }
    >
    > void g1()
    > {
    > cout << Applyf(1.0) << endl ;
    > }
    >
    > file t2.C
    > -----------
    > #include <iostream>
    > #include "t.H"
    >
    > using namespace std ;
    >
    > double f( float x )
    > {
    > return x+x ;
    > }
    >
    > void g2()
    > {
    > cout << Applyf(1.0) << endl ;
    > }
    >
    > file tmain.C
    > -----------------
    >
    > void g1() ;
    > void g2() ;
    >
    > int main( int argc, char * argv[] )
    > {
    > g1() ;
    > g2();
    > }
    >
    >
    > file makefile:
    > ------------------
    > x: a1 a2
    > ./a1
    > ./a2
    > a1:
    > g++ -o a1 t1.C t2.C tmain.C
    >
    > a2:
    > g++ -o a2 t2.C t1.C tmain.C


    In
    void g2()
    {
    cout << Applyf(1.0) << endl ;
    }

    Is called Applyf<double> and it calls f(double). You have to change
    Applyf(1.0) to Applyf(1.0f) to call Applyf<float>.

    Anyway I do not know, why f(double) is found in g2.C compilation unit.
    Ondra Holub, Jan 16, 2007
    #2
    1. Advertising

  3. Guest

    Ondra Holub wrote:
    > napsal:
    > > Hello,
    > > [............]

    >
    > Is called Applyf<double> and it calls f(double). You have to change
    > Applyf(1.0) to Applyf(1.0f) to call Applyf<float>.
    >
    > Anyway I do not know, why f(double) is found in g2.C compilation unit.


    I know you can easily direct the compiler to any version of 'f' you
    wish, but.... the problem is that the criteria it uses (when you do not
    that and it has to choose) seems to be rather unexpected.
    , Jan 16, 2007
    #3
  4. Greg Guest

    wrote:
    > Ondra Holub wrote:
    > > napsal:
    > > > Hello,
    > > > [............]

    > >
    > > Is called Applyf<double> and it calls f(double). You have to change
    > > Applyf(1.0) to Applyf(1.0f) to call Applyf<float>.
    > >
    > > Anyway I do not know, why f(double) is found in g2.C compilation unit.

    >
    > I know you can easily direct the compiler to any version of 'f' you
    > wish, but.... the problem is that the criteria it uses (when you do not
    > that and it has to choose) seems to be rather unexpected.


    Not really. The program can have only one, consistent Applyf<double>()
    specialization - yet this program has created two Applyf<double>()
    specialiations that differ from each other: one calls f(double) and the
    other one calls f(float). Technically these two specializations for
    Applyf<double> violate C++'s "One Definition Rule" (ODR). So the
    behavior of the program is unexpected because it is undefined. As a
    practical matter, which version of Applyf<double> winds up in the
    eventual build is dependent on factors that no build should depend on.

    The fix should be straightfoward. A template function should call only
    those functions that are "visible", that is, that have been declared
    (they need not be defined) before the function template itself.


    Greg
    Greg, Jan 16, 2007
    #4
  5. Guest

    Greg wrote:

    > wrote:
    > > Ondra Holub wrote:
    > > > napsal:
    > > > > Hello,
    > > > > [............]
    > > >
    > > > Is called Applyf<double> and it calls f(double). You have to change
    > > > Applyf(1.0) to Applyf(1.0f) to call Applyf<float>.
    > > >
    > > > Anyway I do not know, why f(double) is found in g2.C compilation unit.

    > >
    > > I know you can easily direct the compiler to any version of 'f' you
    > > wish, but.... the problem is that the criteria it uses (when you do not
    > > that and it has to choose) seems to be rather unexpected.

    >
    > Not really. The program can have only one, consistent Applyf<double>()
    > specialization - yet this program has created two Applyf<double>()
    > specialiations that differ from each other: one calls f(double) and the
    > other one calls f(float). Technically these two specializations for
    > Applyf<double> violate C++'s "One Definition Rule" (ODR). So the
    > behavior of the program is unexpected because it is undefined. As a
    > practical matter, which version of Applyf<double> winds up in the
    > eventual build is dependent on factors that no build should depend on.
    >
    > The fix should be straightfoward. A template function should call only
    > those functions that are "visible", that is, that have been declared
    > (they need not be defined) before the function template itself.
    >
    >
    > Greg


    Thanks a lot, Greg, now the issue is clear to me. I've been reading
    about <a
    href="http://www.slac.stanford.edu/BFROOT/www/Computing/Environment/Standards/C++/cd2/basic.html#basic.def.odr">ODR</a>
    and, if I'm not wrong, it states that violations to it need not be
    allways diagnosed by the compiler/linker, which is the case here with
    gcc/ld (although it usually diagnoses duplicate function definitions).
    I was trying to find an example in which C++ templates flexibility (in
    the sense that C++ allows calls from templates to still non declared
    functions) allows to introduce unexpected behavoir. It seems that I
    have found one --- IMHO, Ada approach to genericity is far more safe.
    , Jan 16, 2007
    #5
    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. Fernando Cuenca
    Replies:
    4
    Views:
    2,522
    Gianni Mariani
    Sep 6, 2004
  2. ES Kim
    Replies:
    4
    Views:
    347
    ES Kim
    Apr 15, 2005
  3. Replies:
    1
    Views:
    570
    Salt_Peter
    Dec 25, 2006
  4. Juha Nieminen

    Template instantiation context

    Juha Nieminen, Jul 18, 2009, in forum: C++
    Replies:
    9
    Views:
    320
    James Kanze
    Jul 20, 2009
  5. Saraswati lakki
    Replies:
    0
    Views:
    1,317
    Saraswati lakki
    Jan 6, 2012
Loading...

Share This Page