question on c++ constants?

G

gpderetta

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

namespace Whatever_Private
{
extern my_functor_type bar ;
} ;

That's the best solution of course. But see at the end.
Or if you really need to be headers only:

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

Well, as my function objects are stateless 99% of the times, if I have
to use an extra set of (), I might as well just instantiate the
function object on the fly. The idea is to use the same syntax for
function objects and functions (i.e. the user doesn't really need to
know if a certain function is really a function or a function object,
up to a point of course).
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.

Often, at least in my code, function objects are compile time
polymorphic (i.e. they have a templated operator(); in fact if it is
not polymorphic there is little need to define a function object in
the first place), so you have to define them in the header anyway.
Having a .cc file just to contain their instantiation is just ugly. I
should probably write a tool that generate such .cc files on the fly
and just add it to the build system.
 
G

gpderetta

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

See James Kanze reply.
Out of curiosity, why?

Because I want my function objects to be as similar as possible as
functions (i.e. to pass a function around you just use its name). And
I need function objects because I can pass them to higher order
functions without having to monomorphize them.
 
J

James Kanze

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;

Not at all. Note the "looked up" in the above paragraph. Names
in a dependent context are not looked up until the template is
instantiated, in the context of the instantiation. (In some
cases, there will be restrictions along the lines that bar may
not be/must be a type or a template, but I don't think any of
those apply here.)
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?

Every name to be looked up is either dependent or not. This is
all spelled out in §14.6, and particularly in §14.6.2: in a
function call where the name of the function is an unqualified
id, the name of the function is dependent if and only if any of
the arguments is a type-dependent expression.
Shall *all* non-dependent names resolve to the same entity in
the context of the template *definition*?

All names looked up in a non-dependent context must resolve to
the same entity at the point of the template definition. (Names
in a dependent context aren't looked up until instantiation.
There's some added confusion because at instantiation time,
names will also be looked up in the context of the template
defintion.)
This isn't the only usage of "ill-formed, with no diagnostic
required".

Probably not. The standard isn't always as coherent in its use
of words as it should be. As it happens, the standard is far
more explicit, and defines violations of the one definition rule
as an explicit exception to the "requiring a diagnostic", see
below.
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.

I don't see how you can get any ill-formedness here without
instantiation. I have no idea how static_assert works, so I
can't be sure there, but in both cases, all of the expressions
are dependent, so analysis won't (and can't) really take place
until instantiation. In particular, although we know that
sizeof(T) can never be less than 1, I don't think that the
compiler can do anything more than a simple syntax check here
until instantiation. Although not an issue directly addressed
by the standard, for example, if T is void or a function or an
incomplete type, the compiler will probably not want to issue
the same diagnosic as it would if T where a complete data type.
I think the compiler requires the first f() to compile, as long
as there is no instantiation (and will require a diagnostic for
all instantations, either because you're taking sizeof of
something which isn't a legal operand of sizeof, or because
you're dividing by zero in an integral constant expression).
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?

Ill-formed applies, first and foremost, to syntax, in its
largest sense. (In any real sense, the fact that the number and
types of the arguments in a function call must agree with the
number and types of the paramters in the declaration is syntax,
in the same way as the fact that the number and gender of an
adjective in French or Italian must agree with the noun it
modifies is syntax.) And requires a compile time diagnostic.
That's what I would expect. The C++ standard defines things
slightly differently, however: an ill-formed program is one that
isn't well-formed, and a well-formed program is "a C++ program
constructed according to the syntax rules, diagnosable semantic
rules, and the One Definition Rule." In other words, violations
of the one definition rule are an explicit exception to the rule
that "ill-formed" requires a diagnostic.

And template definitions, or whatever, aren't ill-formed.
Programs are ill-formed. (Of course, it may be the presence of
a specific definition which renders it 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 :))

Again, the standard defines its own language, to a degree.
 
G

Gennaro Prota

James said:
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;

Not at all. Note the "looked up" in the above paragraph. Names
in a dependent context are not looked up until the template is
instantiated, in the context of the instantiation.

I meant "applied" by the reader of the standard, not by the
compiler. That is: you consult 3.2 to see if the template
definition violates the ODR; 3.2 refers you to clause 14 (for
the template definition). Then clause 14 refers you back to 3.2
for each template instantation. Not sure I managed to explain it
:)
(In some
cases, there will be restrictions along the lines that bar may
not be/must be a type or a template, but I don't think any of
those apply here.)
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?

Every name to be looked up is either dependent or not. This is
all spelled out in §14.6, and particularly in §14.6.2: in a
function call where the name of the function is an unqualified
id, the name of the function is dependent if and only if any of
the arguments is a type-dependent expression.
Shall *all* non-dependent names resolve to the same entity in
the context of the template *definition*?

All names looked up in a non-dependent context must resolve to
the same entity at the point of the template definition. (Names
in a dependent context aren't looked up until instantiation.
There's some added confusion because [...snip]

This is a very important "detail": if *one* dependent usage were
enough to postpone all the lookup to instantiation time then
things would be simpler. Instead, each non-dependent name must
bind uniquely, at definition. Which means that as soon as you
have e.g. bar( 5 )...

Which brings us to the initial point... here you have or not an
ODR violation, depending on the arguments to bar, not just on
its definition: it leads to *easily* to a violation.
Probably not. The standard isn't always as coherent in its use
of words as it should be. As it happens, the standard is far
more explicit, and defines violations of the one definition rule
as an explicit exception to the "requiring a diagnostic", see
below.





I don't see how you can get any ill-formedness here without
instantiation.

Well, the standard says it is ill-formed, instantiated or not. I
said we came upon it recently, but I forgot that it was on
c++.moderated and you didn't get involved. FWIW, the thread is:


<http://google.com/group/comp.lang.c++.moderated/browse_frm/thread/332821427ddca414/0ebc2af6ee0e2f2a>

The relevant wording is in 14.6 [temp.res]:

If no valid specialization can be generated for a template
definition, and that template is not instantiated, the tem-
plate definition is ill-formed, no diagnostic required.

The fact that this is in a section about name resolution makes
one wonder whether it is meant to be applied in all its
generality (anything which doesn't have at least one well-formed
specialization is ill-formed) or just for name issues. In the
example with static_assert there's in fact no name other than T
(off the top of my head I think static_assert declarations and
asm declarations are the only "declarations" which don't declare
a name).

Well, one of the EDG guys (whom I'll not mention because I
haven't asked for his permission to) clarified, privately, that
it was the intent for both examples to be ill-formed. About the
possibility of diagnosing it I don't know... an idea --specific
to these two examples-- might be to have something like an
implicit 'has_size' concept, used internally by the compiler
(not explicitly spelled out by the programmer).

[...]

[...]
And template definitions, or whatever, aren't ill-formed.
Programs are ill-formed. (Of course, it may be the presence of
a specific definition which renders it ill-formed.)

That was my point. And making a whole program invoke UB because
it has an "invalid" template definition which is never
instantiated looks like an exaggeration.
* 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 :))

Again, the standard defines its own language, to a degree.

The principle of least astonishment at work, that is.
 

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,192
Latest member
KalaReid2

Latest Threads

Top