Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Implementing methods of local classes in "global" namespace

84 views
Skip to first unread message

Juha Nieminen

unread,
Oct 27, 2015, 7:08:50 AM10/27/15
to
Consider this:

//--------------------------------------------------
namespace
{
class Foo
{
public:
void bar();
};
}

void Foo::bar() { std::cout << "Hello"; }
//--------------------------------------------------

The class 'Foo' is declared as local to the current compilation unit,
but the Foo::bar() is seemingly defined in global namespace (because
it's outside the nameless namespace block.)

What happens here? Is Foo::bar() local to the current compilation unit?

(I would hope so. This way I can avoid an extra indentation level.)

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Victor Bazarov

unread,
Oct 27, 2015, 8:09:13 AM10/27/15
to
On 10/27/2015 7:08 AM, Juha Nieminen wrote:
> Consider this:
>
> //--------------------------------------------------
> namespace
> {
> class Foo
> {
> public:
> void bar();
> };
> }
>
> void Foo::bar() { std::cout << "Hello"; }
> //--------------------------------------------------
>
> The class 'Foo' is declared as local to the current compilation unit,
> but the Foo::bar() is seemingly defined in global namespace (because
> it's outside the nameless namespace block.)
>
> What happens here? Is Foo::bar() local to the current compilation unit?
>
> (I would hope so. This way I can avoid an extra indentation level.)

The name 'Foo' in the member function declaration/definition is actually
resolved during compilation to something like
'<UniqueToThisSourceFileNamespace>::Foo', where that name is generated
by the compiler, so there should be no worries of its being visible from
outside.

V
--
I do not respond to top-posted replies, please don't ask

Alf P. Steinbach

unread,
Oct 27, 2015, 7:25:29 PM10/27/15
to
On 10/27/2015 12:08 PM, Juha Nieminen wrote:
> Consider this:
>
> //--------------------------------------------------
> namespace
> {
> class Foo
> {
> public:
> void bar();
> };
> }
>
> void Foo::bar() { std::cout << "Hello"; }
> //--------------------------------------------------
>
> The class 'Foo' is declared as local to the current compilation unit,
> but the Foo::bar() is seemingly defined in global namespace (because
> it's outside the nameless namespace block.)
>
> What happens here? Is Foo::bar() local to the current compilation unit?

No, it has external linkage, but it's declared in an anonymous namespace
whose linkage level name will probably be some statistically unique
sequence of letters and digits.

So, in practice it can't be called directly from other translation units.

As for why and how the above code compiles, consider that the following
code is equivalent except for the namespace name:

namespace my {
struct S
{
void foo();
};
} // namespace my

#include <iostream>
using namespace my;

void S::foo() { std::cout << "Oh!\n"; }

auto main() -> int
{
S().foo();
}

Cheers & hth.,

- Alf

Juha Nieminen

unread,
Oct 28, 2015, 4:05:18 AM10/28/15
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> auto main() -> int

Isn't that a bit... of an exaggeration?

David Brown

unread,
Oct 28, 2015, 5:36:23 AM10/28/15
to
On 28/10/15 09:05, Juha Nieminen wrote:
> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> auto main() -> int
>
> Isn't that a bit... of an exaggeration?
>

For some reason, the "int" needs to be explicit for main, at least on
gcc 4.9. Maybe that's just an issue with the partial C14 support in
that version of gcc4.9, and later versions are happy with "auto main()".


Scott Lurndal

unread,
Oct 28, 2015, 9:18:10 AM10/28/15
to
The C++ committee needs someone that can say "no".

int main()

auto main() -> int

how is the latter superior in any way? Why is it a good idea
to have two ways of expressing the same thing?

Juha Nieminen

unread,
Oct 28, 2015, 9:25:17 AM10/28/15
to
Scott Lurndal <sc...@slp53.sl.home> wrote:
> int main()
>
> auto main() -> int
>
> how is the latter superior in any way? Why is it a good idea
> to have two ways of expressing the same thing?

The new alternative syntax is useful with certain template functions
where the type of the return value couldn't be calculated otherwise.
The archetypal example is:

//------------------------------------------
template<class T, class U>
auto add(T t, U u) -> decltype(t + u)
{
return t + u;
}
//------------------------------------------

There is, however, at least one situation where the new syntax actually
makes the function declaration more readable even with a regular
non-templated function:

auto get_fun(int arg) -> double (*)(double)

vs. the old way:

double (*get_fun(int))(double)

Cholo Lennon

unread,
Oct 28, 2015, 9:40:04 AM10/28/15
to
On 10/28/2015 05:05 AM, Juha Nieminen wrote:
> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> auto main() -> int
>
> Isn't that a bit... of an exaggeration?
>

IMHO, yes, but I understand that he is trying to write homogeneous code
everywhere.

This a recurrent topic when Alf P. Steinbach post his code ;-) It's
similar to Stefan Ram usage of ::std:: with the standard library.

Regards

--
Cholo Lennon
Bs.As.
ARG

David Brown

unread,
Oct 28, 2015, 11:01:11 AM10/28/15
to
For functions whose body is known (inline functions, local functions,
etc.), you don't even need to give the type afterwards in C++14:

auto get_fun(int arg) {
return make_function_pointer(arg);
}

The ability to write "auto main() -> int" is just a side-effect of this,
and some people may prefer it if they think it is nice to be consistent.

Mr Flibble

unread,
Oct 28, 2015, 2:01:50 PM10/28/15
to
On 28/10/2015 08:05, Juha Nieminen wrote:
> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> auto main() -> int
>
> Isn't that a bit... of an exaggeration?

Yes it is totally unnecessary but then again Alf is a bit of a tit.

/Flibble

Öö Tiib

unread,
Oct 29, 2015, 7:03:33 AM10/29/15
to
The feature is not that great since implicit return value type is allowing
us to omit important property. That is somewhat like implicit int of C was.
Also we often want to declare functions before defining those (in header)
and there what Juha wrote looks best:

auto get_fun(int arg) -> double (*)(double);

David Brown

unread,
Oct 29, 2015, 8:43:15 AM10/29/15
to
Replacing the return type entirely with auto has the same pros and cons
as using auto in general. It is convenient for complicated types, but
omits information that might be useful to the programmer and reader. It
makes code more flexible (especially for templates), but reduces the
possibilities for type-based error checking. And clearly it can't work
without the function definition (i.e., it will not work in non-defining
declarations).

It's a feature - you can use it if it helps, and avoid it if it does not
help.


Alf P. Steinbach

unread,
Oct 29, 2015, 5:05:05 PM10/29/15
to
On 10/28/2015 2:25 PM, Juha Nieminen wrote:
>
[snip]
>
> There is, however, at least one situation where the new syntax actually
> makes the function declaration more readable even with a regular
> non-templated function:
>
> auto get_fun(int arg) -> double (*)(double)
>
> vs. the old way:
>
> double (*get_fun(int))(double)

Also, old way

Longwinded_class_name::name_of_type Longwinded_class_name::foo(
name_of_type arg
)
{
...
}

versus

auto Longwinded_class_name::foo( name_of_type arg )
-> name_of_type
{
...
}

One less qualification (of the return type), which is also more
consistent, plus more easily recognized fixed placement of the function
name.

However, some people use a formatting convention where the function name
has fixed placement also with the old syntax.


Cheers,

- Alf

Juha Nieminen

unread,
Oct 30, 2015, 5:43:08 AM10/30/15
to
David Brown <david...@hesbynett.no> wrote:
> Replacing the return type entirely with auto has the same pros and cons
> as using auto in general. It is convenient for complicated types, but
> omits information that might be useful to the programmer and reader.

That depends.

The 'auto' variable declaration type is most useful in generic code,
especially templates and functions with 'auto' parameters.

"What, you mean there's other kind of 'generic code' than templates?"
Well, kind of. There are certain situations where it's actually useful
that 'auto' adapts to any changes to a type. The kind of situations where
if you change a type somewhere, then you would need to go through thousands
of lines of code to change the usage of that type. Of course traditionally
this has been circumvented by abstracting the type away with typedef
(which is still a completely valid technique, of course), but in some
situations 'auto' may be a more fluent solution.

In the same vein, there may be situations where we don't actually care
what a type is exactly, because we are not interested in it. A typical
example is something like:

auto x = std::bind(&some_function, _2, _1, some_object);

Here we don't actually care what the type returned by std::bind() is.
We only care about what it does.

And then of course there are situations where 'auto' shortens the code
and makes it cleaner without sacrificing undestandability. The typical
example is:

auto iter = container.begin();

The type of that iterator may sometimes be very long and superfluous.
'auto' is perfect in this situation, and is quite clear what it does.

Of course if abused, like anything else, it can lead to bad code.
You should always know your tools.

Scott Lurndal

unread,
Oct 30, 2015, 9:14:21 AM10/30/15
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

>versus
>
> auto Longwinded_class_name::foo( name_of_type arg )
> -> name_of_type
> {
> ...
> }
>
>One less qualification (of the return type), which is also more
>consistent, plus more easily recognized fixed placement of the function
>name.
>
>However, some people use a formatting convention where the function name
>has fixed placement also with the old syntax.
>

Indeed, as Dennis Richie's convention was

name_of_type
foo(name_of_type)

which meant /^foo in vi would always take one to the
implementation of 'foo'.

Works fine in C++ as well.

e.g. from the version 6 C compiler (circa 1975): c00.c

/*
* Read an expression and return a pointer to its tree.
* It's the classical bottom-up, priority-driven scheme.
* The initflg prevents the parse from going past
* "," or ":" because those delimiters are special
* in initializer (and some other) expressions.
*/
struct tnode *
tree()
{
...
0 new messages