From: Daniel Krügler on 20 Jul 2010 09:48 On 18 Jul., 00:27, Chris Vine <ch...(a)cvine--nospam--.freeserve.co.uk> wrote: > I require a function which must have a C linkage specification (it is a > callback from a C library) to be a friend of a class in order to have > access to protected member functions of the class: it forms part of the > class implementation. Because it has to be a friend it must be > declared in the class header file providing the class definition. > > To minimise intercoupling with other translation units which might look > up the header file, I thought of putting it in anonymous namespace, In general it is a bad idea to use unnamed namespaces within a (shared) header file, because this can easily lead to violations of the ODR, especially if the definition is not (inline) within the header. In case of extern "C" functions this cannot happen, because all of these functions will refer to the same entity. Nevertheless I don't see any reason to confuse readers of your code because of the unnamed namespace. You don't say whether the implementation is in the header or not, so this point is not clear to me. > In order to enable the friend declaration really to make the function a > friend of the class, I need to wrap it in a named namespace, such as: > > I thought every unnamed namespace declaration had with it an implicit > using directive. What is the reason why one friend declaration works > and not the other, It works in the second example, because CB is an *inner* namespace of the unnamed namespace and thus the qualified access via CB::my_callback refers to this entity. Note that ::CB::my_callback would not work either nor does ::my_callback in the first example. The reason for the difference between the first form and the second form is that the first form uses an unqualified name, while the second form uses qualified name. I use the current FCD as reference in the following. As of [namespace.memdef]/3: "Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal class first declares a class or function (footnote) the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [..] If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace. [ Note: the other forms of friend declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules. �end note ]" with footnote: "this implies that the name of the class or function is unqualified." The last quoted normative sentence describes that an unqualified friend declaration checks for previous declarations only the innermost enclosing namespace, which is the global namespace in your original example. The tricky point is, that names introduced in scopes by means of a using-directive don't match with the way unqualified friend-declarations bind to a corresponding entity. As of [basic.lookup.unqual]/2: "The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace." Note that above quote from friend-declaration said: "The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope" but declarations introduced by using-directives don't produce *declarations* in the hosting namespace, these names become only *visible* in that host. This interpretation is supported by [namespace.udir]/2 (emphasize mine): "A using-directive specifies that the names in the nominated namespace **can be used** in the scope in which the using-directive appears after the using- directive. During *unqualified name lookup* (3.4.1), the names *appear as if they were declared* in the nearest enclosing namespace which contains both the using- directive and the nominated namespace. Yes, this subtle difference to normal declarations is hard to recognize, but it exists. Informally, for unqualified friend declarations, names introduced by using-directives are not considered, because they are not declarations within the hosting namespace. [As a side note, there exists a core issue that is involved with friend-declarations and using-declarations, but that one should not affect your example. See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#138 if you are interested in this discussion] Now the difference to the qualified approach: As above quote from [namespace.memdef]/3 implies (see also the last note), *qualified* friend declarations perform the usual look-up rules. In this case the naming of CB::my_callback finds a matching reference, even though this is not ::CB::my_callback. I think this is ruled by 3.4.3.2/7, in particular by the normative sentence: "However, in such namespace member declarations, the nested-name-specifier may rely on using-directives to implicitly provide the initial part of the nested-name-specifier." that follows "In a declaration for a namespace member in which the declarator-id is a qualified-id,[..]" and which should be relevant here. > and is there a better way of doing it, such as by > making the function static? As functions with C linkage do not name > mangle for namespaces (look-up when linking is not affected), is placing > it in anonymous namespace entirely otiose anyway? I would get rid of the unnamed namespace in the header. If the function definition has to be provided in the header, you should declare it as an inline function which prevents violations of the ODR. HTH & Greetings from Bremen Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Francis Glassborow on 20 Jul 2010 09:40 Chris Vine wrote: > > "At most one function with a particular name can have C language > linkage. Two declarations for a function with C language linkage with > the same function name (ignoring the namespace names that qualify it) > that appear in different namespace scopes refer to the same function. > Two declarations for an object with C language linkage with the same > name (ignoring the namespace names that qualify it) that appear in > different namespace scopes refer to the same object. [Note: because of > the one definition rule (3.2), only one definition for a function or > object with C linkage may appear in the program; that is, such a > function or object must not be defined in more than one namespace > scope ..." > > It means that notwithstanding the deprecation of the use of the static > keyword in favour of unnamed namespace, internal linkage via the static > keyword is the only means of isolating a function with C linkage and > preventing a name clash at link time with another function with C > linkage of the same name. Unnamed namespaces appear to be useless for > functions with C linkage. > > In this regard, the one definition rule as formulated in the draft > C++0x standard appears to break C compatibility (including for C++ > programs linking to C libraries). It states that "Every program shall > contain exactly one definition of every non-inline function or variable > that is used in that program; no diagnostic required." It appears to > make no exception for functions with internal linkage (as opposed to > inline functions, for which it does make an exception), but presumably > no sane compiler is actually going to create a name conflict between > two functions wth internal linkage defined in different translation > units where one or more of them are linked in from a C library. > > Chris I cannot quite put my finger on it but I feel that you are missing something. To start with, if you want to link to a C library you must declare a function as extern "C". This isn't just a matter of (the absence) name-mangling in C but that the way that arguments are passed can be different between C and C++ (indeed they certainly were different for the IBM C and C++ compilers, I do not know if they still are) So you require an extern "C" declaration. Now once you have that yjr fact that the declaration is lexically in a namespace becomes irrelevant because there will be no name mangling and the declaration will be exported to global scope. So despite the deprecation of static at namespace scope it is still required in this case if you want to hide a function at file scope. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Chris Vine on 20 Jul 2010 22:04 On Tue, 20 Jul 2010 18:40:37 CST Francis Glassborow <francis.glassborow(a)btinternet.com> wrote: > I cannot quite put my finger on it but I feel that you are missing > something. To start with, if you want to link to a C library you must > declare a function as extern "C". This isn't just a matter of (the > absence) name-mangling in C but that the way that arguments are passed > can be different between C and C++ (indeed they certainly were > different for the IBM C and C++ compilers, I do not know if they > still are) I think we are pretty much on the same page. It is how I got there which is the missing link, as to which see my longer post in response to Daniel Kruegler. I need to pass a function pointer to an external library which must have C linkage for the reasons you describe (otherwise I would use a static member function), which therefore needs to appear in the header in order to be made a friend. In my enthusiasm to avoid namespace pollution I was trying to avoid it having global scope by putting it in some form of unnamed or named namespace. I will give up on that quest. I could still make it static even though its declaration is in the header, as it is not intended that anything will try to link with it - it is class implementation - but whilst that works it causes any other translation units which include the header to give a warning that there is a static function without a definition. I think I will just have a bit of namespace pollution instead. [excess quoting deleted --mod] Chris -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Chris Vine on 20 Jul 2010 22:05 On Tue, 20 Jul 2010 18:49:03 CST Daniel Krügler <daniel.kruegler(a)googlemail.com> wrote: [snip] > Its still unclear to me how you provide your *single* > implementation of the extern "C" function with name > my_callback. Since it is an function with external > linkage there can only be one definition. Since it > is an extern "C" function, all these functions "named" > by different unnamed namespaces are referring to > the same function. So you can only provide a *single* > definition in one translation unit without violating > the ODR. Thank you for your exhaustive analysis of the interaction between friendship and namespaces in your earlier post, which explains the effect I observed. The division between declaration and definition was intended to be entirely conventional. The declaration and associated class definition was in a header file and the implementation was in a separate file (the translation unit) intended for compilation. The function declaration was only in the header file because it needs to be a friend of the class concerned and, because it must be passed as a function pointer having C linkage to an external library, cannot be a static member function . Otherwise, it would be entirely "private" (ie unknown) to the outside world and, knowing what I now know, would have been declared with internal linkage. Given that I am forced for friendship purposes to declare this function in the header file, I thought, entirely wrongly, that including the function declaration within anonymous namespace might provide some useful name mangling which would help prevent name clashes should the same program use the same name in a different translation unit for different purposes, equivalent to giving it internal linkage (which it could still have, in theory, even though it is declared in the header file). > It would violate the ODR, if at least a second translation > unit also provides a definition of my_callback. It is > completely irrelevant, how different the namespace names > are - the namespace protection works only on the > C++ level. Consider: It doesn't do it that way: see above. [snip] > > Unnamed namespaces appear to be useless for functions with C > > linkage. > > This is correct. > > > In this regard, the one definition rule as formulated in the draft > > C++0x standard appears to break C compatibility (including for C++ > > programs linking to C libraries). It states that "Every program > > shall contain exactly one definition of every non-inline function > > or variable that is used in that program; no diagnostic required." > > It appears to make no exception for functions with internal linkage > > (as opposed to inline functions, for which it does make an > > exception), but presumably no sane compiler is actually going to > > create a name conflict between two functions wth internal linkage > > defined in different translation units where one or more of them > > are linked in from a C library. > > This is no break versus C. If you have multiple definitions > of a function named X with internal linkage in different > translation units, all these functions are independent and > different entities, so they are not the same function and > the fact that all of them provide a single definition is > *not* a violation of the ODR. > > The extra-case mentioned for inline functions is necessary, > because the wording gives freedom to provide *multiple* > definitions of the *same* function - this is completely > unique. > > The behaviour of compilers in regard to function definitions > with internal linkage has nothing to do with saneness, it > is required. There are *no* duplicate definitions! In contrast: > If you would omit a single definition of such a function > that is used in the program, you are violating the ODR. OK, thank you for the explanation. I would have hoped that that is what the standard would say but I have to say that is not what it appeared to me to say. Paragraph 3.2/6 of the draft C++0x standard gives a long list of things which may be defined more than once in any one program "provided that each definition appears in a different translation unit", of which functions with internal linkage are not mentioned. I can now see why they were not mentioned: functions with the same name in different translation units with internal linkage can (and usually would) comprise completely different code. The cases mentioned in paragraph 3.2/6 are ones for which the implementation must be the same or equivalent to the same. Chris -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Michael Doubez on 21 Jul 2010 08:19 On 18 juil, 00:27, Chris Vine <ch...(a)cvine--nospam--.freeserve.co.uk> wrote: > I require a function which must have a C linkage specification (it is a > callback from a C library) to be a friend of a class in order to have > access to protected member functions of the class: it forms part of the > class implementation. [snip] There is another technique that I use in those cases: I provide a protected class member function that performs the operation I want on a parameter. And I call it from within the extern "C" function by inheriting the class and breaking encapsulation. In your example: // class definiton class MyClass { protected: void do_it(); // executes do_it() on its parameter static void really_do_it(MyClass& c); }; // class implementation void MyClass::do_it() {} void MyClass::really_do_it(MyClass& c) { c.do_it(); } extern "C" void my_callback(void* data) { struct BreakMyClassEncapuslation: MyClass { using MyClass::really_do_it; }; BreakMyClassEncapuslation::really_do_it(*(static_cast<MyClass*>(data)); } Not the most intuitive but it doesn't leak too much information. In the cases, I cannot modify MyClass, I use a reinterpret cast: extern "C" void my_callback(void* data) { struct BreakMyClassEncapuslation: MyClass { using MyClass::do_it; }; reinterpret_cast<BreakMyClassEncapuslation*>( static_cast<MyClass*>(data)))->do_it(); } But AFAIK it has formally UB. -- Michael [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: templates and default parameters Next: UTF-8 messages in exceptions ? |