Template friend function injection

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • H9XLrv5oXVNvHiUI@spambox.us

    Template friend function injection

    Hi, I have a question about injecting friend functions within template
    classes. My question is specific to gcc (version 3.4.5) used in
    combination with mingw because this code (or at least code that gets
    the same result) works as expected in visualc++. I know that this is
    probably not the right behavior for a compiler but it's the kind of
    behavior I'm searching for so I was hoping there was a way to do the
    same thing in gcc.
    As you know when you define a class (with no template) and within the
    class you define a friend function, the function is injected in the
    scope directly outside of the class itself.

    --- code ---

    void Function();

    int main(int argc, char* argv[])
    {
    Function(); // This works
    }

    class Test
    {
    public:
    friend void Function() { printf("Functio n()"); getchar(); }
    };

    -- end code --


    Now I would like to mimic the same behavior with template classes, but
    this code doesn't work:

    -- code --

    void Function();

    int main(int argc, char* argv[])
    {
    Function(); // This does not work
    }

    template <typename T>
    class Test
    {
    public:
    friend void Function() { printf("Functio n()"); getchar(); }
    };

    template class Test<int>;

    -- end code --

    Specifically I receive an error at link time about Function() not
    being defined, which I guess is due to the compiler not considering
    the definition of Function to be a non-template function and instead
    assuming it to be a template function just because it's defined inside
    of a template class.
    Now, the funny thing is that if you move the main() BELOW the explicit
    instantiation of the template class Test, this code actually compile
    and works, that's why I consider it to be a "bug" because
    theoretically if the definition of Function() is a template function
    (thus not a normal function) it should never be used for the call
    inside of the main() function, whether the main() function is below
    the instantiation or not. Am I right?
    Anyway I'm searching for a way to make the definition of Function()
    available for the main() function even if the main() function is above
    the template instantiation. Is there a way to accomplish this for gcc?
    Like some command-line flag or something? I'd really appreciate that.
    Thanks.
  • =?ISO-8859-1?Q?Marcel_M=FCller?=

    #2
    Re: Template friend function injection

    H9XLrv5oXVNvHiU I@spambox.us wrote:
    -- code --
    >
    void Function();
    >
    int main(int argc, char* argv[])
    {
    Function(); // This does not work
    }
    Obviously you are calling an external version of Function here.

    template <typename T>
    class Test
    {
    public:
    friend void Function() { printf("Functio n()"); getchar(); }
    Now you define Function inline. this is an error.
    };
    >
    template class Test<int>;
    >
    -- end code --
    Specifically I receive an error at link time about Function() not
    being defined, which I guess is due to the compiler not considering
    the definition of Function to be a non-template function and instead
    assuming it to be a template function just because it's defined inside
    of a template class.
    No. It is because Function is declared as extern so far which is
    obviously wrong.
    Now, the funny thing is that if you move the main() BELOW the explicit
    instantiation of the template class Test, this code actually compile
    and works, that's why I consider it to be a "bug" because
    theoretically if the definition of Function() is a template function
    (thus not a normal function) it should never be used for the call
    inside of the main() function, whether the main() function is below
    the instantiation or not. Am I right?
    No. The second approach is valid code. You call Function after it is
    defined inline.
    Anyway I'm searching for a way to make the definition of Function()
    available for the main() function even if the main() function is above
    the template instantiation. Is there a way to accomplish this for gcc?
    Inline functions must be defined before their use. There is no way
    around this.
    I would prefer to define Function outside the body of Test. Like that:


    void Function();

    int main(int argc, char* argv[])
    {
    Function(); // This does not work
    }

    template <typename T>
    class Test
    {
    public:
    friend void Function();
    };

    template class Test<int>;

    void Function()
    { printf("Functio n()"); getchar(); }


    Marcel

    Comment

    • Victor Bazarov

      #3
      Re: Template friend function injection

      Marcel Müller wrote:
      [..]
      Inline functions must be defined before their use. There is no way
      around this.
      [..]
      So, you're saying that the following should not compile/link?

      int foo();
      int main()
      {
      return foo();
      }
      inline int foo() { return 0; } // note the 'inline'

      V
      --
      Please remove capital 'A's when replying by e-mail
      I do not respond to top-posted replies, please don't ask

      Comment

      • H9XLrv5oXVNvHiUI@spambox.us

        #4
        Re: Template friend function injection

        On Jul 11, 5:37 pm, Marcel Müller <news.5.ma...@s pamgourmet.org>
        wrote:
        >
        Obviously you are calling an external version of Function here.
        >
        template <typename T>
        class Test
        {
        public:
           friend void Function() { printf("Functio n()"); getchar(); }
        >
        Now you define Function inline. this is an error.
        >
        Sorry, but why the function is defined as inline if I define it inside
        of a template and it is not if I define it inside of a normal class?

        >
        No. It is because Function is declared as extern so far which is
        obviously wrong.
        >
        Well, then this page is wrong (or at least confusing):

        It says:
        "After the compiler sees that magic stuff, it will be better informed
        about the friend functions. In particular, it will realize that the
        friend lines are referring to functions that are themselves templates.
        That eliminates the confusion.

        Another approach is to define the friend function within the class
        body at the same moment you declare it to be a friend."
        >
        No. The second approach is valid code. You call Function after it is
        defined inline.
        >
        Then it means that the code in the first section (when the function
        Function() is defined within the non-template class) should be wrong
        too, and thus signaled by the compiler/linker, isn't it?
        >
        Inline functions must be defined before their use. There is no way
        around this.
        I would prefer to define Function outside the body of Test. Like that:
        >
        void Function();
        >
        int main(int argc, char* argv[])
        {
                Function(); // This does not work
        >
        }
        >
        template <typename T>
        class Test
        {
        public:
                friend void Function();
        >
        };
        >
        template class Test<int>;
        >
        void Function()
        { printf("Functio n()"); getchar(); }
        >
        Marcel
        Unluckily I can't do that because the whole purpose of this approach
        was to do something with T inside of the Function() function. Using
        templates so that the function is defined only at the very final
        moment when someone instantiate the Test class with some template
        argument.

        Comment

        • gpderetta

          #5
          Re: Template friend function injection

          On Jul 11, 4:30 pm, H9XLrv5oXVNvH.. .@spambox.us wrote:
          <snip>
          As you know when you define a class (with no template) and within the
          class you define a friend function, the function is injected in the
          scope directly outside of the class itself.
          >
          AFAIK friend injection is prestandard behavior. The standard requires
          friend functions defined inside a class *not* to
          be injected in the namespace the class is defined in. The only way to
          call such a function is via argument dependent lookup (thus a nullary
          inline friend function cannot be called at all). Older GCCs accepted
          such code by default, but this extension has been removed from recent
          GCCs. There might be an option to re-enable this feature , but it is
          better to fix the code.

          HTH,

          --
          gpd

          Comment

          • H9XLrv5oXVNvHiUI@spambox.us

            #6
            Re: Template friend function injection

            On Jul 11, 6:09 pm, gpderetta <gpdere...@gmai l.comwrote:
            On Jul 11, 4:30 pm, H9XLrv5oXVNvH.. .@spambox.us wrote:
            <snip>As you know when you define a class (with no template) and withinthe
            class you define a friend function, the function is injected in the
            scope directly outside of the class itself.
            >
            AFAIK friend injection is prestandard behavior.  The standard requires
            friend functions defined inside a class *not* to
            be injected in the namespace the class is defined in. The only way to
            call such a function is via argument dependent lookup (thus a nullary
            inline friend function cannot be called at all). Older GCCs accepted
            such code by default, but this extension has been removed from recent
            GCCs. There might be an option to re-enable this feature , but it is
            better to fix the code.
            >
            HTH,
            >
            --
            gpd
            Well the problem is that I was hoping in this trick to use a
            particular technique.
            Also in the GCC documentation there's written that the thing that's
            not allowed is to declare AND define a friend function within a class,
            thus creating a new symbol and injecting the function itself.
            Instead you must first declare the function in the scope you're
            injecting it in and then you can "inject" just the body of that
            function and that's exactly what I'm doing. I could be wrong though,
            that's why I'm asking here if there's any way to accomplish this.

            Comment

            • Victor Bazarov

              #7
              Re: Template friend function injection

              gpderetta wrote:
              On Jul 11, 4:30 pm, H9XLrv5oXVNvH.. .@spambox.us wrote:
              <snip>
              >As you know when you define a class (with no template) and within the
              >class you define a friend function, the function is injected in the
              >scope directly outside of the class itself.
              >>
              AFAIK friend injection is prestandard behavior. The standard requires
              friend functions defined inside a class *not* to
              be injected in the namespace the class is defined in.
              The difference with the OP's case, however, is that the function is
              already in the namespace scope by virtue of having been declared there.
              The only way to
              call such a function is via argument dependent lookup (thus a nullary
              inline friend function cannot be called at all). Older GCCs accepted
              such code by default, but this extension has been removed from recent
              GCCs. There might be an option to re-enable this feature , but it is
              better to fix the code.
              >
              HTH,
              >
              --
              gpd
              V
              --
              Please remove capital 'A's when replying by e-mail
              I do not respond to top-posted replies, please don't ask

              Comment

              • H9XLrv5oXVNvHiUI@spambox.us

                #8
                Re: Template friend function injection

                On Jul 11, 6:37 pm, Victor Bazarov <v.Abaza...@com Acast.netwrote:
                gpderetta wrote:
                On Jul 11, 4:30 pm, H9XLrv5oXVNvH.. .@spambox.us wrote:
                <snip>
                As you know when you define a class (with no template) and within the
                class you define a friend function, the function is injected in the
                scope directly outside of the class itself.
                >
                AFAIK friend injection is prestandard behavior.  The standard requires
                friend functions defined inside a class *not* to
                be injected in the namespace the class is defined in.
                >
                The difference with the OP's case, however, is that the function is
                already in the namespace scope by virtue of having been declared there.
                >
                 The only way to
                >
                call such a function is via argument dependent lookup (thus a nullary
                inline friend function cannot be called at all). Older GCCs accepted
                such code by default, but this extension has been removed from recent
                GCCs. There might be an option to re-enable this feature , but it is
                better to fix the code.
                >
                HTH,
                >
                --
                gpd
                >
                V
                --
                Please remove capital 'A's when replying by e-mail
                I do not respond to top-posted replies, please don't ask
                So does it mean that my syntax of function injection is standard-
                compliant? And do you know of a way to accomplish the same thing
                within the template class?

                Comment

                • =?ISO-8859-1?Q?Marcel_M=FCller?=

                  #9
                  Re: Template friend function injection

                  H9XLrv5oXVNvHiU I@spambox.us wrote:
                  On Jul 11, 5:37 pm, Marcel Müller <news.5.ma...@s pamgourmet.org>
                  wrote:
                  >Obviously you are calling an external version of Function here.
                  >>
                  >>template <typename T>
                  >>class Test
                  >>{
                  >>public:
                  >> friend void Function() { printf("Functio n()"); getchar(); }
                  >Now you define Function inline. this is an error.
                  >>
                  >
                  Sorry, but why the function is defined as inline if I define it inside
                  of a template and it is not if I define it inside of a normal class?
                  It is always inline. However in case of a normal class the compiler does
                  not assume, that the function is not used by another object module in a
                  way that does not allow inline - e.g. taking the address. Therefore the
                  compiler always generates the code for the non-inline function and
                  associates it with a weak symbol. If it is not used or if there are
                  multiple implementations on linkage, the linker discards superfluous
                  instances.
                  In case of templates the compiler behaves different. Since templates
                  have always to be defined before usage. The compiler generates the
                  non-inline code only on demand in the current object module. The
                  explicit template instantiation is not sufficient for that.

                  >No. The second approach is valid code. You call Function after it is
                  >defined inline.
                  >>
                  >
                  Then it means that the code in the first section (when the function
                  Function() is defined within the non-template class) should be wrong
                  too, and thus signaled by the compiler/linker, isn't it?
                  No, that's fine. The compile only silently calls the non-inline version
                  of Function because it does not yet have an implementation.

                  However, Alf P.Steinbach is right. The standard does not make such
                  restrictions. It mainly defines that it is not an error to have
                  redundant symbols in different object modules in this case. It always up
                  to the compiler to inline the code or not.
                  But from the implementation point of view, it is obvious that you cannot
                  inline a function before their definition. That would require a two-pass
                  compilation.

                  >I would prefer to define Function outside the body of Test. Like that:
                  >
                  Unluckily I can't do that because the whole purpose of this approach
                  was to do something with T inside of the Function() function. Using
                  templates so that the function is defined only at the very final
                  moment when someone instantiate the Test class with some template
                  argument.
                  I expected something like that. That still gives you the chance, to use
                  the functions defined inside Test not before the definition of test.

                  Furthermore you can define a template version of Function outside Test
                  for this purpose.


                  Marcel

                  Comment

                  • H9XLrv5oXVNvHiUI@spambox.us

                    #10
                    Re: Template friend function injection

                    On Jul 11, 6:53 pm, Marcel Müller <news.5.ma...@s pamgourmet.org>
                    wrote:
                    I expected something like that. That still gives you the chance, to use
                    the functions defined inside Test not before the definition of test.
                    >
                    Furthermore you can define a template version of Function outside Test
                    for this purpose.
                    >
                    Marcel
                    Can you explain this point better? Especially the last sentence. If I
                    define a template version of Function() then I would not be able to
                    call it from main, am I wrong? Can you provide an example? Thank you.

                    Comment

                    • Victor Bazarov

                      #11
                      Re: Template friend function injection

                      H9XLrv5oXVNvHiU I@spambox.us wrote:
                      [..]
                      So does it mean that my syntax of function injection is standard-
                      compliant? And do you know of a way to accomplish the same thing
                      within the template class?
                      From all I could gather by reading the Standard and other posts, there
                      is nothing wrong with your code even when the template is involved.
                      [temp.friend]/5 says:
                      <quote>
                      When a function is defined in a friend function declaration in a class
                      template, the function is defined at each instantiation of the class
                      template. The function is defined even if it is never used. The same
                      restrictions on multiple declarations and definitions which apply to
                      non-template function declarations and definitions also apply to these
                      implicit definitions.
                      </quote>

                      The function is inline (implicitly), it's defined (per that paragraph)
                      when you instantiate your template.

                      VC++ 9 (Visual Studio 2008) chokes on the module throwing C1001 (ICE) on
                      the line that contains the friend declaration. Why, I don't know. I do
                      not know whether it's been already reported as a bug, either. I'll ask
                      in the Visual C++ newsgroup. As for GCC, you would have to ask them.
                      Comeau C++ (online) compiles it fine; it doesn't link, so I am not sure
                      if everything's OK with their ability to handle that code.

                      V
                      --
                      Please remove capital 'A's when replying by e-mail
                      I do not respond to top-posted replies, please don't ask

                      Comment

                      • H9XLrv5oXVNvHiUI@spambox.us

                        #12
                        Re: Template friend function injection

                        On Jul 11, 7:21 pm, Victor Bazarov <v.Abaza...@com Acast.netwrote:
                        H9XLrv5oXVNvH.. .@spambox.us wrote:
                        [..]
                        So does it mean that my syntax of function injection is standard-
                        compliant? And do you know of a way to accomplish the same thing
                        within the template class?
                        >
                         From all I could gather by reading the Standard and other posts, there
                        is nothing wrong with your code even when the template is involved.
                        [temp.friend]/5 says:
                        <quote>
                        When a function is defined in a friend function declaration in a class
                        template, the function is defined at each instantiation of the class
                        template. The function is defined even if it is never used. The same
                        restrictions on multiple declarations and definitions which apply to
                        non-template function declarations and definitions also apply to these
                        implicit definitions.
                        </quote>
                        >
                        The function is inline (implicitly), it's defined (per that paragraph)
                        when you instantiate your template.
                        >
                        VC++ 9 (Visual Studio 2008) chokes on the module throwing C1001 (ICE) on
                        the line that contains the friend declaration.  Why, I don't know.  Ido
                        not know whether it's been already reported as a bug, either.  I'll ask
                        in the Visual C++ newsgroup.  As for GCC, you would have to ask them.
                        Comeau C++ (online) compiles it fine; it doesn't link, so I am not sure
                        if everything's OK with their ability to handle that code.
                        >
                        V
                        --
                        Please remove capital 'A's when replying by e-mail
                        I do not respond to top-posted replies, please don't ask
                        So my code involving the template class and function injection is
                        correct and standard-compliant.

                        As for GCC it compiles the code just fine but as I said it doesn't
                        link it because it misses the Function() function. It says that's not
                        defined.
                        Now I don't know if this is due to the function definition for some
                        reason not "matching" the declaration (for instance because it is
                        treated like a template function) or because somehow the function body
                        is completely "skipped" (for instance because the function gets
                        inlined).
                        From what I know a function gets inlined only when declaration and
                        definition occur in the same place, which is not true for my code.
                        So is there any possibility that this is a GCC bug?

                        Comment

                        • Victor Bazarov

                          #13
                          Re: Template friend function injection

                          H9XLrv5oXVNvHiU I@spambox.us wrote:
                          [..]
                          So my code involving the template class and function injection is
                          correct and standard-compliant.
                          Yes, IMNSHO.
                          As for GCC it compiles the code just fine but as I said it doesn't
                          link it because it misses the Function() function. It says that's not
                          defined.
                          Now I don't know if this is due to the function definition for some
                          reason not "matching" the declaration (for instance because it is
                          treated like a template function) or because somehow the function body
                          is completely "skipped" (for instance because the function gets
                          inlined).
                          You probably can examine the contents of the object code (.o file) and
                          find out what functions you have defined there. I would be you have at
                          least 'main'. <UnixRTFM about 'nm' (IIRC) utility. </Unix>
                          From what I know a function gets inlined only when declaration and
                          definition occur in the same place, which is not true for my code.
                          Is that code different from what you posted?
                          So is there any possibility that this is a GCC bug?
                          Bug? In GCC?! Nah...

                          V
                          --
                          Please remove capital 'A's when replying by e-mail
                          I do not respond to top-posted replies, please don't ask

                          Comment

                          • H9XLrv5oXVNvHiUI@spambox.us

                            #14
                            Re: Template friend function injection

                            On Jul 11, 7:53 pm, Victor Bazarov <v.Abaza...@com Acast.netwrote:
                            H9XLrv5oXVNvH.. .@spambox.us wrote:
                            [..]
                            So my code involving the template class and function injection is
                            correct and standard-compliant.
                            >
                            Yes, IMNSHO.
                            >
                            As for GCC it compiles the code just fine but as I said it doesn't
                            link it because it misses the Function() function. It says that's not
                            defined.
                            Now I don't know if this is due to the function definition for some
                            reason not "matching" the declaration (for instance because it is
                            treated like a template function) or because somehow the function body
                            is completely "skipped" (for instance because the function gets
                            inlined).
                            >
                            You probably can examine the contents of the object code (.o file) and
                            find out what functions you have defined there. I would be you have at
                            least 'main'. <UnixRTFM about 'nm' (IIRC) utility. </Unix>
                            >
                            Yes, the problem is that on windows with mingw at least the object
                            files are outputted on the temporary folder and deleted as far as the
                            compilation fails. I guess there's some kind of command-line argument
                            to tell gcc not to delete them or to put them somewhere I say it to,
                            but I'm not very used to gcc so I'll have to find it out.
                            From what I know a function gets inlined only when declaration and
                            definition occur in the same place, which is not true for my code.
                            >
                            Is that code different from what you posted?
                            >
                            I don't understand the question. I'm talking about the code I posted,
                            which doesn't compile as well as my real code I'm working on.
                            So is there any possibility that this is a GCC bug?
                            >
                            Bug? In GCC?! Nah...
                            >
                            Well if Bush became president 2 consecutive times, everything is
                            possible.
                            V
                            --
                            Please remove capital 'A's when replying by e-mail
                            I do not respond to top-posted replies, please don't ask

                            Comment

                            • Victor Bazarov

                              #15
                              Re: Template friend function injection

                              H9XLrv5oXVNvHiU I@spambox.us wrote:
                              On Jul 11, 7:53 pm, Victor Bazarov <v.Abaza...@com Acast.netwrote:
                              >H9XLrv5oXVNvH. ..@spambox.us wrote:
                              >>[..]
                              >>From what I know a function gets inlined only when declaration and
                              >>definition occur in the same place, which is not true for my code.
                              >Is that code different from what you posted?
                              >>
                              >
                              I don't understand the question. I'm talking about the code I posted,
                              which doesn't compile as well as my real code I'm working on.
                              I wasn't sure whether you meant the code you posted or some other code
                              in which the template and its explicit instantiation were in a different
                              (than 'main') translation unit. Can you try your code on a different
                              compiler? I am going to try in GCC on Linux. Will report with results
                              in a few minutes...

                              V
                              --
                              Please remove capital 'A's when replying by e-mail
                              I do not respond to top-posted replies, please don't ask

                              Comment

                              Working...