question on c++ constants?

S

Stephen Horne

James said:
[..]
There is a very strong technical argument for *not* putting them
in anonymous namespace.

There is? Care to provide it?

Since each body file and therefore each object file gets its own copy
of the constant, you have multiple copies. Despite the constness, one
or more could be modified (const_cast, memory corruption etc).

Of course if you're modifying your constants, you're probably digging
a hole for yourself anyway. In fact you could argue that having
multiple copies might limit the scope of errors resulting from memory
corruption - though it could just as easily confuse you when you're
trying to debug that memory corruption.

Personally, I don't see a "very strong" argument. I wouldn't do it
myself, but that's as far as I'd go.
 
S

Stephen Horne

Please answer the concrete question. What would be the reason to have
constants in the *anonymous* namespace as compared to the *global*
namespace? Concrete answer, please. If you don't have one, say so.

I'm missing something here. I thought "don't pollute the global
namespace" was a concrete answer.
 
J

James Kanze

James said:
[..]
There is a very strong technical argument for *not* putting
them in anonymous namespace.
There is? Care to provide it?

Yes. It leads too easily to violations of the one definition
rule. It doesn't do what is usually wanted.
Why? Please don't mind me. Explain as if a newbie was
asking.

Because it leads to accidental violations of the one definition
rule. Remember that for the multiple definitions (e.g. of
classes, templates or inline functions) to not be inviolation of
the one definition rule, not only must the token sequence in the
definition be identical; all symbols must also bind identically
as well. The only exception is if the symbol binds to a const
object, with a visible initializer, and only the value is used
(e.g. it's either used in a context which requires a const
expression, or there is an immediate lvalue to rvalue
conversion). Refer to almost anything in an anonymous namespace
in a header, and you end up with undefined behavior.
To which rule?

The the rule not to use anonymous namespace in a header.

Like all rules, it admits exceptions. But as it is a good
general rule, it's better to follow it unless there are
distinct reasons for not doing so. In this case, there's no
real advantage in breaking it, so it's probably better to
respect it.
 
G

gpderetta

James said:
[..]
There is a very strong technical argument for *not* putting
them in anonymous namespace.
There is?  Care to provide it?

Yes.  It leads too easily to violations of the one definition
rule.  It doesn't do what is usually wanted.
Why?  Please don't mind me.  Explain as if a newbie was
asking.

Because it leads to accidental violations of the one definition
rule.  Remember that for the multiple definitions (e.g. of
classes, templates or inline functions) to not be inviolation of
the one definition rule, not only must the token sequence in the
definition be identical; all symbols must also bind identically
as well.  The only exception is if the symbol binds to a const
object, with a visible initializer, and only the value is used
(e.g. it's either used in a context which requires a const
expression, or there is an immediate lvalue to rvalue
conversion).  Refer to almost anything in an anonymous namespace
in a header, and you end up with undefined behavior.

Is this exception explicitly given in the standard or must be inferred
somehow? Do you have a pointer?

Thanks,
 
J

James Kanze

Never had that problem myself

I haven't either. But I've very conservative in my use of
overloading and templates; there are cases where it makes a
difference.
- I'm careful how I overload my integers for reasons that are
nothing to do with enum, and everything to do with my failed
portable code ideals. You never know whether int will be
considered the same type as long int and so on - even though
they're normally the same type in the set-of-values sense, and
have been since the days of 16-bit ints.

int and long int are never the same type. At least not with a
conforming compiler, and I've never encountered compiler which
didn't conform in this regard. (It was, after all, already the
rule in K&R C.)

As for both supporting the same set-of-values, I don't know. In
terms of different types of systems, probably not---most Unix
systems have 64 bit longs, but 32 bit ints. In terms of numbers
of machines, I'm not up to date as to what is being used in the
embedded world (which probably accounts for something like 90%
of all machines)---when I worked in it, 8 bit processors were
the rule, and 16 bit machines were considered really big.
(There's also the question as to how relevant this is to C++.
One common processor when I worked in embedded software only had
64 bytes of RAM. Somehow, I'm sure that even if it's still
around, it doesn't have a C++ compiler. Using std::vector in 64
bytes would be somewhat of a challenge.)
Enums are still being used - old habits die hard - it's just
that it's naughtier than it used to be.

I forget when I made the move over, but it wasn't all that long
ago. And the reason I delayed was that I had to support a
compiler which didn't support initializers in the class
definition for static const ints. Still, given the way most
people seem to overload and use templates, it's probably best
avoided.
 
G

Gennaro Prota

gpderetta said:
Is this exception explicitly given in the standard or must be inferred
somehow? Do you have a pointer?

An unnamed namespace goes --as per language definition-- like
this

namespace unique { }
using namespace unique ;
namespace unique { /* your stuff */ }

where "unique" is a name generated by the compiler, unique per
*translation unit* (not file). So, if you include e.g.

// a.hpp
namespace {
class A {} ;
}

from e.g. f1.cpp and f2.cpp you end up with two A classes, one
in namespace --let's call it-- f1_unique, and another one in
f2_unique. Now, consider two source files which include the
following:

// useful.hpp
#include "a.hpp"

class useful
{
A a_ ;
...
} ;

Those two source files will contain two different definitions of
class useful.
 
G

gpderetta

An unnamed namespace goes --as per language definition-- like
this

   namespace unique { }
   using namespace unique ;
   namespace unique { /* your stuff */ }

where "unique" is a name generated by the compiler, unique per
*translation unit* (not file). So, if you include e.g.

   // a.hpp
   namespace {
     class A {} ;
   }

from e.g. f1.cpp and f2.cpp you end up with two A classes, one
in namespace --let's call it-- f1_unique, and another one in
f2_unique. Now, consider two source files which include the
following:

   // useful.hpp
   #include "a.hpp"

   class useful
   {
     A a_ ;
     ...
   } ;

Those two source files will contain two different definitions of
class useful.

I'm aware of that, I was referring to the exception stated by James
Kanze:

" The only exception is if the symbol binds to a const
object, with a visible initializer, and only the value is used
(e.g. it's either used in a context which requires a const
expression, or there is an immediate lvalue to rvalue
conversion "
 
G

gpderetta

An unnamed namespace goes --as per language definition-- like
this
  namespace unique { }
  using namespace unique ;
  namespace unique { /* your stuff */ }
where "unique" is a name generated by the compiler, unique per
*translation unit* (not file). So, if you include e.g.
  // a.hpp
  namespace {
    class A {} ;
  }
from e.g. f1.cpp and f2.cpp you end up with two A classes, one
in namespace --let's call it-- f1_unique, and another one in
f2_unique. Now, consider two source files which include the
following:
  // useful.hpp
  #include "a.hpp"
  class useful
  {
    A a_ ;
    ...
  } ;
Those two source files will contain two different definitions of
class useful.

This is a great example that could lead to quite an obscure coding
guideline.  Of course, a good compiler would issue a warning if a type
from an unnamed namespace would be used to define another type which
isn't in the [same] unnamed namespace.  We could lobby the compiler
vendors to include such analysis, it wouldn't be difficult for them to
introduce, I suppose.

It is not just a matter of types, consider this:

// in foo.hpp
struct my_functor_type {...};

namespace { my_functor_type bar; }

template<class T> void foo(T x) {
bar(x);
}

Now, if foo is instantiated in two translation units with the same T,
it will lead to ODR violation.
This is not a made up example, I often find the need to name function
object instances in header files, but, if the anonymous namespace is
dropped, you will get multiple definitions for 'bar'.
The only workaround I know (from the boost mailing list) is:

template <class F> struct instance_of { static T value; };
template<class T> T instance_of<T>::value = {}

namespace { my_functor_type const& bar =
instance_of<my_functor_type>::value; }
template<class T> void foo(T x) {
bar(x);
}

Now there won't be any ODR violations in 'foo', if the ODR rule is
interpret as only requiring all symbols to bind to the same objects in
all translation units.

The idea is that, as per the standard, a reference is not an object
but is really an alias for an object (which will be the same for all
translation units: the compiler will take care of that).
 
G

Gennaro Prota

gpderetta said:
I'm aware of that, I was referring to the exception stated by James
Kanze:

" The only exception is if the symbol binds to a const
object, with a visible initializer, and only the value is used
(e.g. it's either used in a context which requires a const
expression, or there is an immediate lvalue to rvalue
conversion "

Ah, sorry, I misread your post. Well it's in the standard ODR
prayer, in clause 3 (note that it is restricted to objects with
internal linkage or no linkage).
 
G

Gennaro Prota

gpderetta said:
It is not just a matter of types, consider this:

// in foo.hpp
struct my_functor_type {...};

namespace { my_functor_type bar; }

template<class T> void foo(T x) {
bar(x);
}

Now, if foo is instantiated in two translation units with the same T,
it will lead to ODR violation.

Do you mean that there's no violation if you instantiate on
different T's?
This is not a made up example, I often find the need to name function
object instances in header files,

Out of curiosity, why?
 
G

Gennaro Prota

Victor Bazarov wrote:
[...]
This is a great example that could lead to quite an obscure coding
guideline.

Why obscure?
Of course, a good compiler would issue a warning if a type
from an unnamed namespace would be used to define another type which
isn't in the [same] unnamed namespace. We could lobby the compiler
vendors to include such analysis, it wouldn't be difficult for them to
introduce, I suppose.

I'd love if we had such a power. But do we? (FWIW, I've never
liked the Boost praxis of supporting all broken compilers of the
world; at least, if the library becomes attractive to many
users, and it doesn't work with their compiler, they may put
pressure, complain or switch to another one; if it is supported,
instead, how can you expect the vendor to improve it?)
 
S

Stephen Horne

namespace SomeSpecificYetUnknownFromOutsideName {
your declarations;
}

using namespace SomeSpecificYetUnknownFromOutsideName;

What is this if not "polluting" the global namespace?

Depends what you mean by *global* namespace. They pollute the source
code that includes them, but they don't pollute the linkers namespace,
which is more likely the point. Global *within* a set of compilation
units isn't the same as simply global.
Wake up, Stephen!

I'm awake - I just recognise that if someone #includes a header, they
are obviously *requesting* a certain amount of namespace "pollution",
local to that particular compilation unit. In a large project,
however, it can be important to limit the effect of that pollution to
the source files that specifically request it.

You can't program without polluting namespaces to a degree - even a
namespace pollutes its parent namespace. Different degrees of
pollution are appropriate to the global namespace depending on what
you mean by "global".
 
S

Stephen Horne

Those two source files will contain two different definitions of
class useful.

Which are both in different namespaces. Impossible to provide
implementation stuff unless it/they are already fully implemented, but
even so. It does what it's supposed to do, in accordance with the
standard.

More to the point, every construct has unsafe uses, and every style
guideline is inherently an overgeneralisation WRT avoiding those
unsafe uses. Different people have differing style rules, implying
differing generalisations of what is unsafe.

The original example was using constants. Criticising that is valid,
if you have a legitimate criticism. Criticising it because putting
*other* stuff in an anonymous namespace in a header is unsafe, IMO, is
not.

Pushing the principle to an extreme, you may as well say that all
values should be banned because a reinterpret_cast of any value is
unsafe.
 
I

Ian Collins

Stephen said:
Which are both in different namespaces.

No, they are not. Please don't snip away the code you are referring to,
doing so makes your postings meaningless.

The example was

#include "a.hpp"

class useful
{
A a_ ;
...
} ;

where A was declared in a.hpp in an unnamed namespace.
Impossible to provide
implementation stuff unless it/they are already fully implemented, but
even so. It does what it's supposed to do, in accordance with the
standard.
What?

More to the point, every construct has unsafe uses, and every style
guideline is inherently an overgeneralisation WRT avoiding those
unsafe uses. Different people have differing style rules, implying
differing generalisations of what is unsafe.
The quoted example is well passed unsafe.
The original example was using constants. Criticising that is valid,
if you have a legitimate criticism. Criticising it because putting
*other* stuff in an anonymous namespace in a header is unsafe, IMO, is
not.
How can we tell when you removed it?
Pushing the principle to an extreme, you may as well say that all
values should be banned because a reinterpret_cast of any value is
unsafe.
Twaddle.
 
S

Stephen Horne

#include "a.hpp"

class useful
{
A a_ ;
...
} ;

Whoops - yes, you're right. Sorry - brain failure - I though "useful"
was in the anonymous namespace.
How can we tell when you removed it?

No-one is going to spend that much time second-guessing whether
they've left sufficient context in a post. My bad, but you only need
to make the point once.

After getting the point that was actually being made, it obviously
extends to constants, but *maybe* it could be argued that it depends
on the constant. In the context (which someone else snipped, not me)
we're talking about these...

: const double PI = 3.14159;
: const double g = 9.81;
: const double inch = 25.4;

A class may have constants with values derived from these. I doubt
that it would become double-defined because of that, since the values
remain the same, but I could be wrong.

There are possibilities that *would* cause double definition, but they
seem pretty unlikely.

Of course once you start a list of constants, it's an invitation for
more to be added, and once you get an array size or some such...

So yes, I'm wrong on this one, thinking it through properly. I still
think there's a get-out clause for that particular usage, but I
wouldn't have said what I said if I understood the point being made.

Sorry for being such an idiot.
 
J

James Kanze

This is a great example that could lead to quite an obscure
coding guideline. Of course, a good compiler would issue a
warning if a type from an unnamed namespace would be used to
define another type which isn't in the [same] unnamed
namespace. We could lobby the compiler vendors to include
such analysis, it wouldn't be difficult for them to introduce,
I suppose.

Except that it's actually very frequent for a class to use
something defined in an anonymous namespace. There's nothing
wrong with that, and banning it, or even warning about it, would
make the compilation firewall idiom a pain.

What the compiler could warn about is if a definition (any
definition) in a header file (but not e.g. the definition of
Toto::Impl, which is in Toto.cc) used a definition from an
anonymous namespace in an illegal way. Although I suspect that
it might be difficult to implement the warning when the use is
in a template, especially if it is in a dependent context. (Of
course, it's so easy to get violations of the one definition
rule in dependent contexts that one more probably doesn't matter
much.)

The real issue is, given the risk, are there any legal cases
where one might legitimately want to use an anonymous namespace
in a header. I can't think of one, really: if I'm using the
symbol in a header, about the only time the use would be legal
is if the symbol is a constant, and in that case, the anonymous
namespace really buys you nothing, since const variables have
internal linkage by default.
Not sure if tools like PC-lint already have a way to recognize
this kind of a problem. Anybody has any idea?

Have a rule forbidding anonymous namespaces in a header file:).
 
J

James Kanze

Gennaro said:
gpderetta wrote:
[...]
Refer to almost anything in an anonymous namespace
in a header, and you end up with undefined behavior.
Is this exception explicitly given in the standard or
must be inferred somehow? Do you have a pointer?
An unnamed namespace goes --as per language definition--
like this
namespace unique { }
using namespace unique ;
namespace unique { /* your stuff */ }
where "unique" is a name generated by the compiler, unique
per *translation unit* (not file). So, if you include e.g.
// a.hpp
namespace {
class A {} ;
}
from e.g. f1.cpp and f2.cpp you end up with two A classes, one
in namespace --let's call it-- f1_unique, and another one in
f2_unique. Now, consider two source files which include the
following:
// useful.hpp
#include "a.hpp"
class useful
{
A a_ ;
...
} ;
Those two source files will contain two different
definitions of class useful.
This is a great example that could lead to quite an obscure coding
guideline. Of course, a good compiler would issue a warning if a type
from an unnamed namespace would be used to define another type which
isn't in the [same] unnamed namespace. We could lobby the compiler
vendors to include such analysis, it wouldn't be difficult for them to
introduce, I suppose.
It is not just a matter of types, consider this:
// in foo.hpp
struct my_functor_type {...};
namespace { my_functor_type bar; }
template<class T> void foo(T x) {
bar(x);
}
Now, if foo is instantiated in two translation units with the
same T, it will lead to ODR violation.

Yes. This is what I consider the real problem. Templates
require their definition to be in the header file, and the
one definition rule to apply to all potential instantiations
(even if in practice, most compilers will just pick one, and
throw out any others).
This is not a made up example, I often find the need to name
function object instances in header files, but, if the
anonymous namespace is dropped, you will get multiple
definitions for 'bar'. The only workaround I know (from the
boost mailing list) is:
template <class F> struct instance_of { static T value; };
template<class T> T instance_of<T>::value = {}
namespace { my_functor_type const& bar =
instance_of<my_functor_type>::value; }
template<class T> void foo(T x) {
bar(x);
}

Typical Boost:). Why do simple when you can do complicated:

namespace Whatever_Private
{
extern my_functor_type bar ;
} ;

Or if you really need to be headers only:

namespace Whatever_Private
{
inline my_functor_type& bar()
{
static my_functor_type theOneAndOnly ;
return theOneAndOnly ;
}
} ;

In sum, the classical solutions (but it just ain't Boost if it
ain't got the templates).

(Seriously, there's a lot I like about Boost. But they do get
carried away sometimes.)
Now there won't be any ODR violations in 'foo', if the ODR
rule is interpret as only requiring all symbols to bind to the
same objects in all translation units.

If you want the library to be headers only, then you need to
encapsulate the definition in something which can appear in
multiple compilation units: a template or an inline function.
Generally, you're better off dropping the headers only
requirement, however.
 
J

James Kanze

Do you mean that there's no violation if you instantiate on
different T's?

Not in this case. It's being used in a dependent context, so
name binding doesn't occur until instantiation. The applicable
part is the last couple of sentences in §14.6.4.1: "A
specialization for any template may have points of instantiation
in multiple translation units. If two different points of
instantiation give a template specialization different meanings
according to the one definition rule, the program is ill-formed,
no diagnostic required." (Which seems to be a contradiction in
itself: ill-formed means that a diagnostic is required,
otherwise, it's undefined behavior.)
Out of curiosity, why?

Because it gives an excuse to use more templates:).

The cases where you need a non-local instance at all are
probably very, very rare. But even then, C++ supports global
variables very well, and if you really need headers only---say
because you've imposed a really broken build system---then
there's always the classical and universally known inline
function returning a reference to a local static idiom.
 
J

James Kanze

On 2008-10-16 15:46:06 -0400, Gennaro Prota <gennaro/[email protected]> said:
Sometimes vendors fix things without having to hear screams
that Boost doesn't work. Library vendors who don't work around
problems in order to provoke screams usually find that the
screams are aimed at them.

It's also a chicken and egg problem. If the library doesn't
work with the most widespread compilers (and let's face it, not
so many years ago, all of the compilers were seriously broken
with regards to standard conforming templates), it won't be
attractive to many users. There's nothing attractive about a
library I can't use.

Boost's attitude here has actually had very positive effects.
Thanks to the work-arounds, the library did become widespread
and attractive. To the point that many compiler vendors
consider it an explicit target to be able to compile it
completely without using the work-arounds. Without Boost, some
of the template features it uses would probably have far lower
priority with the compiler implementors.

Now if only it required export... :).
 
G

Gennaro Prota

James said:
Not in this case. It's being used in a dependent context, so
name binding doesn't occur until instantiation. The applicable
part is the last couple of sentences in §14.6.4.1: "A
specialization for any template may have points of instantiation
in multiple translation units. If two different points of
instantiation give a template specialization different meanings
according to the one definition rule, the program is ill-formed,
no diagnostic required."

Ah, right. So 3.2 [basic.def.odr] p5:

in each definition of D, corresponding names, looked up
according to 3.4, shall refer to an entity defined within the
definition of D, or shall refer to the same entity, after
overload resolution (13.3) and after matching of partial
template specialization (14.8.3) [...]

must first be applied with D being the function template, just
to be pointed to 3.4; then (once back from 3.4, which leads to
14.6.4.1) again with D being each function template
instantiation (i.e. each template function).

But here we have just one name in the body of foo (ignoring the
trivial case of 'x'). If we have several, some being dependent
and some non-dependent, how is 3.2 to be interpreted? Shall
*all* non-dependent names resolve to the same entity in the
context of the template *definition*?
(Which seems to be a contradiction in
itself: ill-formed means that a diagnostic is required,
otherwise, it's undefined behavior.)

This isn't the only usage of "ill-formed, with no diagnostic
required". Another one we came upon recently is the case in
which no valid specialization of a template can be generated:
the template definition is ill-formed (and, so, the whole
program?) and no diagnostic is required:

template< typename T >
void f()
{
1 / ( sizeof( T ) == 0 ) ;
}

template< typename T >
void f()
{
static_assert( sizeof( T ) == 0, "" ) ;
}

It remains a bit unclear to me what does it concretely mean for
a template definition to be ill-formed when it is never
instantiated. Among other things:

* AFAICS, "ill-formed" applies to (is defined for) a program.
When the standard says the template definition is
ill-formed, does it mean that the program which contains it
is ill-formed?

* According to 1.4 [intro.compliance] bullet 3, it seems that
a program containing such a template definition invokes UB.
But is that the intent? It seems a bit over the top.

(Incidentally, there's also another point about terminology:
"diagnosable rule" suggests "rule that *may* be diagnosed", not
that "must be diagnosed". This example is about a rule which may
be diagnosed, but isn't diagnosable :))
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,197
Latest member
ScottChare

Latest Threads

Top