C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Violation of the ODR?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Fuz
Guest





PostPosted: Thu Dec 29, 2005 3:26 pm    Post subject: Violation of the ODR? Reply with quote



Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT>
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int>

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S<float>

It's a *declaration* violation, but not 'definition', as far as I can
tell.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Bob Hairgrove
Guest





PostPosted: Fri Dec 30, 2005 1:28 am    Post subject: Re: Violation of the ODR? Reply with quote



On 29 Dec 2005 10:26:39 -0500, "Fuz"
<srobb (AT) reflectionsinteractive (DOT) com> wrote:

Quote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S
It's a *declaration* violation, but not 'definition', as far as I can
tell.

I don't see why it wouldn't compile. But aside from the "violation or
not" issue, why do you think it is necessary (or even just cool) to do
it this way? I suppose one justification would be to prohibit
inclusion of your header by other source files which don't define
DEFAULT.

--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Luke Meyers
Guest





PostPosted: Sat Dec 31, 2005 1:12 pm    Post subject: Re: Violation of the ODR? Reply with quote



Fuz wrote:
Quote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S<float

It's a *declaration* violation, but not 'definition', as far as I can
tell.

By the time the preprocessor's done, you have something like:

template struct S
{
T t;
};

S<> s1;

template <typename T = float>
struct S
{
T t;
};

S<> s2;

You've defined it (the template) twice. Specifying a different default
template parameter doesn't make it a different template. If you put
the braces in, that's the definition, not just a declaration. You're
relying on one definition hiding another.

Luke


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Victor Bazarov
Guest





PostPosted: Sat Dec 31, 2005 1:14 pm    Post subject: Re: Violation of the ODR? Reply with quote

Fuz wrote:
Quote:
Is the following a violation of the One Definition Rule?

No.

Quote:
// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S
It's a *declaration* violation, but not 'definition', as far as I can
tell.

Why do you think that it is a "declaration violation"? 14.1/12 only
prohibits having [the same] default template-argument in two declarations
in _the_same_ scope. Yours are two different translation units, which
makes them two different scopes.

There is no violation. The program is well-formed.

V



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Luke Meyers
Guest





PostPosted: Sat Dec 31, 2005 1:26 pm    Post subject: Re: Violation of the ODR? Reply with quote

Oops, in my original response I missed the part where you had two
different cpp files.

Since they're separate compilation units, how could there be a
compilation error? It's a linker question, really, and I don't think
the linker would object. Though, yes, it's odd.

Luke


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Wil Evers
Guest





PostPosted: Sat Dec 31, 2005 1:31 pm    Post subject: Re: Violation of the ODR? Reply with quote

Fuz wrote:

Quote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S

That depends. If source1.cpp and source2.cpp end up in the same program,
then yes, you're violating the ODR.

Quote:
It's a *declaration* violation, but not 'definition', as far as I can
tell.

No. You're using different *definitions* of the struct S class template.

- Wil


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
H.A.W.K.
Guest





PostPosted: Sat Dec 31, 2005 1:35 pm    Post subject: Re: Violation of the ODR? Reply with quote


Fuz wrote:
Quote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S<float

It's a *declaration* violation, but not 'definition', as far as I can
tell.

Look at this:

// header.h
template struct S
{
T t;
};

// header2.h
template <typename T = float>
struct S
{
T t;
};

// source1.cpp
#include "header.h"

S<> s1; // decltype(s1) == S<int>

// source2.cpp
#include "header2.h"

S<> s2; // decltype(s2) == S<float>

All that you've done is generating two DIFFERENT headers using
preproccesor.

Best regards and happy new year,
Jaroslaw "H.A.W.K." Skrzypek


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Fuz
Guest





PostPosted: Sat Dec 31, 2005 7:09 pm    Post subject: Re: Violation of the ODR? Reply with quote


Bob Hairgrove wrote:
Quote:
I don't see why it wouldn't compile. But aside from the "violation or
not" issue, why do you think it is necessary (or even just cool) to do
it this way? I suppose one justification would be to prohibit
inclusion of your header by other source files which don't define
DEFAULT.

Oh, it may well compile. I just don't know if it's actually legal.

There's a valid reason behind this code. The defaulted parameter is an
error handling policy which the class uses for handling/reporting
precondition violations. In general, you use a project-wide default,
but a particular translation unit may choose to use a different policy.
This could be done by defining a macro before including the header, in
a similar way to how the <cassert> header allows selective compilation
of assertions by definition of the NDEBUG macro.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze
Guest





PostPosted: Sat Dec 31, 2005 7:26 pm    Post subject: Re: Violation of the ODR? Reply with quote

Fuz wrote:
Quote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S<float

Yes. In practice, it's one that almost certainly won't cause
problems (except for the poor bloke reading the code, and trying
to figure out what it does).

A more useful (and frequent) violation is:

// header.hh
#include
template< typename T >
void
f( T t )
{
assert( t.isValid() ) ;
}

// source1.cc
#include <header.hh>

// source2.cc
#include <header.hh>

Where source1.cc is compiled with the -DNDEBUG flag, and
source2.cc not.

Note that this is true even though the template is never
instantiated.

Quote:
It's a *declaration* violation, but not 'definition', as far
as I can tell.

Which is supposed to mean?

In header.h, you have a statement which defines the class
template S. §3.2/5 says:

Given such an entity [e.g. a template definition] named D
defined in more than one translation unit, then

-- each definition of D shall consist of the same sequence
of tokens [condition met here]; and

-- 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 and after matching of
partial template specialization, except [...]

[...]

Your example fails this second case. A definition is a type of
statement, with a specific syntax, and the default parameters in
this case, are part of the definition.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Greg Herlihy
Guest





PostPosted: Sun Jan 01, 2006 11:21 am    Post subject: Re: Violation of the ODR? Reply with quote

Fuz wrote:
Quote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S<float

It's a *declaration* violation, but not 'definition', as far as I can
tell.

This example may not be a violation of the one definition rule (ODR)
though it certainly violates the standards of good taste Smile.

Assuming that the question is not merely of academic interest - and
there is in fact some compelling reason for varying the type of an S<>
declaration, then I would at least make the implementation more "C++
like".

Specifically, replace the macro with a typedef. Of course a "Default"
typedef in the global namespace must be consistently defined in order
to adhere to the ODR, but a typedef in an anonymous namespace has no
such limitation:

in source1.cpp:

namespace {
typedef int Default;
}

#include "header.h"

in source2.cpp:

namespace {
typedef float Default;
}

#include "header.h"

in header.h:

template <class T = Default>
struct S
{
...
};

Note that the result is as questionable as ever, but by avoiding the
macro and by using legitimate C++ techniques, the implementation now at
least has a veneer of respectability.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Wil Evers
Guest





PostPosted: Sun Jan 01, 2006 11:23 am    Post subject: Re: Violation of the ODR? Reply with quote

Victor Bazarov wrote:

Quote:
Fuz wrote:

Is the following a violation of the One Definition Rule?

No.

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S

[ snip ]

Quote:
14.1/12 only
prohibits having [the same] default template-argument in two declarations
in _the_same_ scope. Yours are two different translation units, which
makes them two different scopes.

There is no violation. The program is well-formed.

I can see how 14.1/12 can lead to this interpretation. However, if
source1.cpp and source2.cpp end up in the same program, 3.2/5 specifically
requires the class template definitions in source1.cpp and source2.cpp to
consist of the same token sequence. Obviously, after preprocessing, these
token sequences differ, so we do have an ODR violation here.

- Wil


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Fuz
Guest





PostPosted: Mon Jan 02, 2006 10:22 am    Post subject: Re: Violation of the ODR? Reply with quote


kanze wrote:

Quote:
In header.h, you have a statement which defines the class
template S. §3.2/5 says:

Given such an entity [e.g. a template definition] named D
defined in more than one translation unit, then

-- each definition of D shall consist of the same sequence
of tokens [condition met here]; and

-- 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 and after matching of
partial template specialization, except [...]

[...]

Your example fails this second case. A definition is a type of
statement, with a specific syntax, and the default parameters in
this case, are part of the definition.

I agree with your reasoning, however, I debate that the default
parameters are part of a definition. I don't have my copy of the
Standard to hand right now, but here is some empirical evidence based
on a transformation of my first example:

template <typename T>
struct S
{
T t;
};

template <typename T = int>
struct S;

S<> s1; // decltype(s1) == S<int>


I've tested this code with a variety of compilers (Comeau 4.3.3 Beta
(Online), VC++7.0, VC++8.0, GCC 3.4, Digital Mars 8.3Cool, and they all
allow the declaration of S with a default parameter after the
definition. This should not be possible if, as you state, default
parameters are part of the definition, as you'd be redefining S in the
same scope - something we definitely know is illegal. Of course, all
these compilers could be wrongly allowing it.

The only problem I found is that the VC++s complained about the use of
S<> in the declaration of s1, saying that the S template requires 1
parameter; however, they did not complain about the 'redefinition of
S'. This suggests (to me) a parsing error on the part of VC, or at
least the lack of an appropriate error diagnostic on the 'redefinition
of S', if it is in fact illegal.

It's certainly an odd case, and one which I'll avoid, but I'd still
like a definitive answer as to its legality.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Greg Herlihy
Guest





PostPosted: Mon Jan 02, 2006 11:41 am    Post subject: Re: Violation of the ODR? Reply with quote

kanze wrote:
Quote:
Fuz wrote:
Is the following a violation of the One Definition Rule?

// header.h
template <typename T = DEFAULT
struct S
{
T t;
};

// source1.cpp
#define DEFAULT int
#include "Header.h"

S<> s1; // decltype(s1) == S<int

// source2.cpp
#define DEFAULT float
#include "Header.h"

S<> s2; // decltype(s2) == S<float

It's a *declaration* violation, but not 'definition', as far
as I can tell.

Which is supposed to mean?

In header.h, you have a statement which defines the class
template S. §3.2/5 says:

Given such an entity [e.g. a template definition] named D
defined in more than one translation unit, then

-- each definition of D shall consist of the same sequence
of tokens [condition met here]; and

Actually, this example would not meet a "same sequence of tokens"
condition since preprocessor tokens are converted into tokens [see
§2.1/7]. So in this case the DEFAULT macro is not consistently
converted into the same token, so the complete token sequence varies.

However the ODR exempts class templates from the "same sequence of
tokens" condition [§3.2/5] And in fact this exemption makes sense -
otherwise merely replacing "class" with "typename" in a template
definition would violate the ODR. So it is not in fact necessary that a
macro be consistently defined when it appears in a class template
definition.

Quote:
-- 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 and after matching of
partial template specialization, except [...]

[...]

Your example fails this second case. A definition is a type of
statement, with a specific syntax, and the default parameters in
this case, are part of the definition.

In that case there is still a supported, though slightly convulated
workaround. Declare S within an anonymous namespace:

// header.h
namespace
{
template class S
{
...
};
}

And each source file can declare the "Default" typedef in an anonymous
namespace of its own:

// source1.cpp:
namespace
{
typedef int Default;
}

#include "header.h"

static S<> s; // S<int>

and:

// source2.cpp:
namespace
{
typedef float Default;
}

#include "header.h"

static S s<>; // S<float>

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Francis Glassborow
Guest





PostPosted: Mon Jan 02, 2006 3:59 pm    Post subject: Re: Violation of the ODR? Reply with quote

In article <1136124516.783366.121430 (AT) z14g2000cwz (DOT) googlegroups.com>, Fuz
<srobb (AT) reflectionsinteractive (DOT) com> writes
Quote:
I've tested this code with a variety of compilers (Comeau 4.3.3 Beta
(Online), VC++7.0, VC++8.0, GCC 3.4, Digital Mars 8.3Cool, and they all
allow the declaration of S with a default parameter after the
definition. This should not be possible if, as you state, default
parameters are part of the definition, as you'd be redefining S in the
same scope - something we definitely know is illegal. Of course, all
these compilers could be wrongly allowing it.

This is a false argument. The breaches of the ODR explicitly do not
require diagnostics. That is not to say that your conclusion is false,
just that you can not use compiler acceptance as any form of 'proof'.
Now in the case in point, the default is a type and I suspect that a
close examination of the Standard might make that legal, however the
Standard has to cope with such things as:

template< typename int, void (fn_ptr)(int) = foo >
class example {
....
};

Now if in TU 1 we find:
void foo(int = 0);
and in TU 2 we have
void foo(int = 1);

We have the potential for a ODR violation.

The above may well be not entirely correct, but the principle is. WG21
had very serious problems with how to specify what would be an ODR
breach in the context of function declarations that include default
parameters.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Francis Glassborow
Guest





PostPosted: Mon Jan 02, 2006 4:00 pm    Post subject: Re: Violation of the ODR? Reply with quote

In article <43b69d5d$0$11075$e4fe514c (AT) news (DOT) xs4all.nl>, Wil Evers
<bouncer (AT) dev (DOT) null> writes
Quote:
I can see how 14.1/12 can lead to this interpretation. However, if
source1.cpp and source2.cpp end up in the same program, 3.2/5 specifically
requires the class template definitions in source1.cpp and source2.cpp to
consist of the same token sequence. Obviously, after preprocessing, these
token sequences differ, so we do have an ODR violation here.

WG21 had serious problems because requiring the same token sequence was
neither necessary nor sufficient to ensure non-breach of the ODR. They
compromised by making the requirement of 3.2/5 which I suspect does make
the use of typename in one TU and class in another a technical ODR
violation. However as breaches of the ODR do not require diagnostics,
IIRC, they decided to ignore that problem.

I fail to see the relevance of 14.1/12 unless we are lumping together
all global declarations in all TUs as being in the same scope. I think
that would be a stretch and would likely have other implications as
well.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.