Why can't forward declared friend class be referred in the class?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
23
down vote

favorite
4












The following code doesn't compile:



struct X 
friend class Y;
Y* ptr;
;


The cppreference describes the situation as




... If the name of the class that is used in the friend declaration is
not yet declared, it is forward declared on the spot.




If the "spot" means where the friend relationship is declared, then it should be fine to declare the member Y* ptr. Why doesn't it compile? Where in the standard prohibits this?







share|improve this question
















  • 3




    @edtheprogrammerguy MSVC being able to compile something isn't the best of tests. both Clang and GCC fail to compile.
    – NathanOliver
    Aug 27 at 18:21






  • 1




    Please provide the specific compiler errors that you are seeing along with what compiler and version you are using.
    – Richard Chambers
    Aug 27 at 18:23










  • Ahh, that's not what "spot" means.
    – Eljay
    Aug 27 at 18:30






  • 2




    Minimal (non-)Compilable Verifiable Example with gcc and clang
    – jaggedSpire
    Aug 27 at 18:31















up vote
23
down vote

favorite
4












The following code doesn't compile:



struct X 
friend class Y;
Y* ptr;
;


The cppreference describes the situation as




... If the name of the class that is used in the friend declaration is
not yet declared, it is forward declared on the spot.




If the "spot" means where the friend relationship is declared, then it should be fine to declare the member Y* ptr. Why doesn't it compile? Where in the standard prohibits this?







share|improve this question
















  • 3




    @edtheprogrammerguy MSVC being able to compile something isn't the best of tests. both Clang and GCC fail to compile.
    – NathanOliver
    Aug 27 at 18:21






  • 1




    Please provide the specific compiler errors that you are seeing along with what compiler and version you are using.
    – Richard Chambers
    Aug 27 at 18:23










  • Ahh, that's not what "spot" means.
    – Eljay
    Aug 27 at 18:30






  • 2




    Minimal (non-)Compilable Verifiable Example with gcc and clang
    – jaggedSpire
    Aug 27 at 18:31













up vote
23
down vote

favorite
4









up vote
23
down vote

favorite
4






4





The following code doesn't compile:



struct X 
friend class Y;
Y* ptr;
;


The cppreference describes the situation as




... If the name of the class that is used in the friend declaration is
not yet declared, it is forward declared on the spot.




If the "spot" means where the friend relationship is declared, then it should be fine to declare the member Y* ptr. Why doesn't it compile? Where in the standard prohibits this?







share|improve this question












The following code doesn't compile:



struct X 
friend class Y;
Y* ptr;
;


The cppreference describes the situation as




... If the name of the class that is used in the friend declaration is
not yet declared, it is forward declared on the spot.




If the "spot" means where the friend relationship is declared, then it should be fine to declare the member Y* ptr. Why doesn't it compile? Where in the standard prohibits this?









share|improve this question











share|improve this question




share|improve this question










asked Aug 27 at 18:12









Kan Li

3,27833176




3,27833176







  • 3




    @edtheprogrammerguy MSVC being able to compile something isn't the best of tests. both Clang and GCC fail to compile.
    – NathanOliver
    Aug 27 at 18:21






  • 1




    Please provide the specific compiler errors that you are seeing along with what compiler and version you are using.
    – Richard Chambers
    Aug 27 at 18:23










  • Ahh, that's not what "spot" means.
    – Eljay
    Aug 27 at 18:30






  • 2




    Minimal (non-)Compilable Verifiable Example with gcc and clang
    – jaggedSpire
    Aug 27 at 18:31













  • 3




    @edtheprogrammerguy MSVC being able to compile something isn't the best of tests. both Clang and GCC fail to compile.
    – NathanOliver
    Aug 27 at 18:21






  • 1




    Please provide the specific compiler errors that you are seeing along with what compiler and version you are using.
    – Richard Chambers
    Aug 27 at 18:23










  • Ahh, that's not what "spot" means.
    – Eljay
    Aug 27 at 18:30






  • 2




    Minimal (non-)Compilable Verifiable Example with gcc and clang
    – jaggedSpire
    Aug 27 at 18:31








3




3




@edtheprogrammerguy MSVC being able to compile something isn't the best of tests. both Clang and GCC fail to compile.
– NathanOliver
Aug 27 at 18:21




@edtheprogrammerguy MSVC being able to compile something isn't the best of tests. both Clang and GCC fail to compile.
– NathanOliver
Aug 27 at 18:21




1




1




Please provide the specific compiler errors that you are seeing along with what compiler and version you are using.
– Richard Chambers
Aug 27 at 18:23




Please provide the specific compiler errors that you are seeing along with what compiler and version you are using.
– Richard Chambers
Aug 27 at 18:23












Ahh, that's not what "spot" means.
– Eljay
Aug 27 at 18:30




Ahh, that's not what "spot" means.
– Eljay
Aug 27 at 18:30




2




2




Minimal (non-)Compilable Verifiable Example with gcc and clang
– jaggedSpire
Aug 27 at 18:31





Minimal (non-)Compilable Verifiable Example with gcc and clang
– jaggedSpire
Aug 27 at 18:31













3 Answers
3






active

oldest

votes

















up vote
27
down vote



accepted










This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:




7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.




The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.






share|improve this answer




















  • So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
    – Richard Chambers
    Aug 27 at 18:32










  • @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
    – n.m.
    Aug 27 at 18:33










  • @n.m. so the class Y; would need to be at whatever scope the class definition is located.
    – Richard Chambers
    Aug 27 at 18:34










  • @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
    – R Sahu
    Aug 27 at 18:36






  • 4




    I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
    – Barmar
    Aug 27 at 20:41

















up vote
2
down vote













In addition to the answer of @dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:




10 [ Note: Friend declarations refer to functions or classes that are
members of the nearest enclosing namespace, but they do not introduce
new names into that namespace ([namespace.memdef]).







share|improve this answer



























    up vote
    0
    down vote













    One way to fix this code is to simply add class keyword:



    struct X 
    friend class Y;
    class Y* ptr;
    ;


    This will forward declare class Y at the global scope, if X is in the global scope.






    share|improve this answer






















    • This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
      – aschepler
      Aug 28 at 3:50










    • @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
      – Evg
      Aug 28 at 7:24










    Your Answer





    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52044848%2fwhy-cant-forward-declared-friend-class-be-referred-in-the-class%23new-answer', 'question_page');

    );

    Post as a guest






























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    27
    down vote



    accepted










    This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:




    7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.




    The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.






    share|improve this answer




















    • So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
      – Richard Chambers
      Aug 27 at 18:32










    • @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
      – n.m.
      Aug 27 at 18:33










    • @n.m. so the class Y; would need to be at whatever scope the class definition is located.
      – Richard Chambers
      Aug 27 at 18:34










    • @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
      – R Sahu
      Aug 27 at 18:36






    • 4




      I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
      – Barmar
      Aug 27 at 20:41














    up vote
    27
    down vote



    accepted










    This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:




    7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.




    The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.






    share|improve this answer




















    • So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
      – Richard Chambers
      Aug 27 at 18:32










    • @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
      – n.m.
      Aug 27 at 18:33










    • @n.m. so the class Y; would need to be at whatever scope the class definition is located.
      – Richard Chambers
      Aug 27 at 18:34










    • @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
      – R Sahu
      Aug 27 at 18:36






    • 4




      I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
      – Barmar
      Aug 27 at 20:41












    up vote
    27
    down vote



    accepted







    up vote
    27
    down vote



    accepted






    This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:




    7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.




    The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.






    share|improve this answer












    This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:




    7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.




    The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Aug 27 at 18:29









    dasblinkenlight

    597k547411165




    597k547411165











    • So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
      – Richard Chambers
      Aug 27 at 18:32










    • @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
      – n.m.
      Aug 27 at 18:33










    • @n.m. so the class Y; would need to be at whatever scope the class definition is located.
      – Richard Chambers
      Aug 27 at 18:34










    • @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
      – R Sahu
      Aug 27 at 18:36






    • 4




      I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
      – Barmar
      Aug 27 at 20:41
















    • So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
      – Richard Chambers
      Aug 27 at 18:32










    • @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
      – n.m.
      Aug 27 at 18:33










    • @n.m. so the class Y; would need to be at whatever scope the class definition is located.
      – Richard Chambers
      Aug 27 at 18:34










    • @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
      – R Sahu
      Aug 27 at 18:36






    • 4




      I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
      – Barmar
      Aug 27 at 20:41















    So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
    – Richard Chambers
    Aug 27 at 18:32




    So if you put class Y; before the friend class Y; at that point the class Y is declared and can then be used.
    – Richard Chambers
    Aug 27 at 18:32












    @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
    – n.m.
    Aug 27 at 18:33




    @RichardChambers but it would declare class Y that is local to X, not Y in the surrounding namespace.
    – n.m.
    Aug 27 at 18:33












    @n.m. so the class Y; would need to be at whatever scope the class definition is located.
    – Richard Chambers
    Aug 27 at 18:34




    @n.m. so the class Y; would need to be at whatever scope the class definition is located.
    – Richard Chambers
    Aug 27 at 18:34












    @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
    – R Sahu
    Aug 27 at 18:36




    @RichardChambers, yes. However, IMO, it's poor coding practice to use the friend declaration to also declare a class. It will be better to delcare the class first before using the friend declaration.
    – R Sahu
    Aug 27 at 18:36




    4




    4




    I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
    – Barmar
    Aug 27 at 20:41




    I suspect what the quoted sentence is trying to say is that you don't need a forward declaration in order to declare a friend, it's implicitly forward-declared for that purpose.
    – Barmar
    Aug 27 at 20:41












    up vote
    2
    down vote













    In addition to the answer of @dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:




    10 [ Note: Friend declarations refer to functions or classes that are
    members of the nearest enclosing namespace, but they do not introduce
    new names into that namespace ([namespace.memdef]).







    share|improve this answer
























      up vote
      2
      down vote













      In addition to the answer of @dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:




      10 [ Note: Friend declarations refer to functions or classes that are
      members of the nearest enclosing namespace, but they do not introduce
      new names into that namespace ([namespace.memdef]).







      share|improve this answer






















        up vote
        2
        down vote










        up vote
        2
        down vote









        In addition to the answer of @dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:




        10 [ Note: Friend declarations refer to functions or classes that are
        members of the nearest enclosing namespace, but they do not introduce
        new names into that namespace ([namespace.memdef]).







        share|improve this answer












        In addition to the answer of @dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:




        10 [ Note: Friend declarations refer to functions or classes that are
        members of the nearest enclosing namespace, but they do not introduce
        new names into that namespace ([namespace.memdef]).








        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Aug 27 at 18:44









        Stephan Lechner

        21.9k21637




        21.9k21637




















            up vote
            0
            down vote













            One way to fix this code is to simply add class keyword:



            struct X 
            friend class Y;
            class Y* ptr;
            ;


            This will forward declare class Y at the global scope, if X is in the global scope.






            share|improve this answer






















            • This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
              – aschepler
              Aug 28 at 3:50










            • @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
              – Evg
              Aug 28 at 7:24














            up vote
            0
            down vote













            One way to fix this code is to simply add class keyword:



            struct X 
            friend class Y;
            class Y* ptr;
            ;


            This will forward declare class Y at the global scope, if X is in the global scope.






            share|improve this answer






















            • This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
              – aschepler
              Aug 28 at 3:50










            • @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
              – Evg
              Aug 28 at 7:24












            up vote
            0
            down vote










            up vote
            0
            down vote









            One way to fix this code is to simply add class keyword:



            struct X 
            friend class Y;
            class Y* ptr;
            ;


            This will forward declare class Y at the global scope, if X is in the global scope.






            share|improve this answer














            One way to fix this code is to simply add class keyword:



            struct X 
            friend class Y;
            class Y* ptr;
            ;


            This will forward declare class Y at the global scope, if X is in the global scope.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Aug 28 at 7:09

























            answered Aug 27 at 19:36









            Evg

            2,2351130




            2,2351130











            • This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
              – aschepler
              Aug 28 at 3:50










            • @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
              – Evg
              Aug 28 at 7:24
















            • This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
              – aschepler
              Aug 28 at 3:50










            • @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
              – Evg
              Aug 28 at 7:24















            This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
            – aschepler
            Aug 28 at 3:50




            This will not "forward declare" anything, as it does not make it possible to use the name Y alone like a real declaration would. This makes Y a member of the global scope only if X is also directly in the global scope. More generally, that code will twice use the Y which is associated with the innermost enclosing namespace or block scope.
            – aschepler
            Aug 28 at 3:50












            @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
            – Evg
            Aug 28 at 7:24




            @aschepler It was assumed that X was in the global scope, I refined my answer. Could you please explain your first sentence? What is the difference between class Y; struct X friend class Y; Y* ptr; ; and the code in my answer?
            – Evg
            Aug 28 at 7:24

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52044848%2fwhy-cant-forward-declared-friend-class-be-referred-in-the-class%23new-answer', 'question_page');

            );

            Post as a guest













































































            這個網誌中的熱門文章

            How to combine Bézier curves to a surface?

            Mutual Information Always Non-negative

            Why am i infinitely getting the same tweet with the Twitter Search API?