Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > conflicting declaration in template static member

Reply
Thread Tools

conflicting declaration in template static member

 
 
Michael Doubez
Guest
Posts: n/a
 
      03-24-2011
Hello,

I have the following minimal code:

template< class T >
struct Foo {
static int const N = T::size;
static int values[N];
};
template< class T > int const Foo<T>::N;
template< class T > int Foo<T>::values[Foo<T>::N] = {};

struct Bar {
enum { size = 42 } ;
};

int main() {
Foo<Bar> f;
return f.N;
}

Which yield under gcc (4.1.3 and 4.3.3):
error: conflicting declaration 'int Foo<T>::values [Foo::N]
error: 'Foo<T>::values' has a previous declaration as 'int
Foo<T>::values [Foo<T>::N]'
error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
class is not definition

The compiler seems confused by the size because it accepts the code
- if I replace the definition of N by:
enum { N = T::size };
- if I don't use N but T::size

This code pass under Comeau online (not in codepad).

Is this a compiler bug or is it expected behavior ?

--
Michael
 
Reply With Quote
 
 
 
 
puppi
Guest
Posts: n/a
 
      03-24-2011
On Mar 24, 6:18*am, Michael Doubez <michael.dou...@free.fr> wrote:
> Hello,
>
> I have the following minimal code:
>
> template< class T >
> struct Foo {
> * * static int const N = T::size;
> * * static int values[N];};
>
> template< class T > int const Foo<T>::N;
> template< class T > int * * * * *Foo<T>::values[Foo<T>::N] = {};
>
> struct Bar {
> * * enum { size = 42 } ;
>
> };
>
> int main() {
> * * Foo<Bar> f;
> * * return f.N;
>
> }
>
> Which yield under gcc (4.1.3 and 4.3.3):
> error: conflicting declaration 'int Foo<T>::values [Foo::N]
> error: 'Foo<T>::values' has a previous declaration as 'int
> Foo<T>::values [Foo<T>::N]'
> error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
> class is not definition
>
> The compiler seems confused by the size because it accepts the code
> * *- if I replace the definition of N by:
> enum { N = T::size };
> * - if I don't use N but T::size
>
> This code pass under Comeau online (not in codepad).
>
> Is this a compiler bug or is it expected behavior ?
>
> --
> Michael


Well, under gcc 4.4.5 it compiles fine...
Have you tried to remove the declaration/initialization pair:
template< class T > int const Foo<T>::N;
template< class T > int Foo<T>::values[Foo<T>::N] = {};
Since they really aren't necessary, trying to remove them would be my
first try.
 
Reply With Quote
 
 
 
 
Paul
Guest
Posts: n/a
 
      03-24-2011

"Michael Doubez" <> wrote in message
news:fa47db15-24c8-4861-83f9-...
> Hello,
>
> I have the following minimal code:
>
> template< class T >
> struct Foo {
> static int const N = T::size;
> static int values[N];
> };
> template< class T > int const Foo<T>::N;
> template< class T > int Foo<T>::values[Foo<T>::N] = {};
>
> struct Bar {
> enum { size = 42 } ;
> };
>
> int main() {
> Foo<Bar> f;
> return f.N;
> }
>
> Which yield under gcc (4.1.3 and 4.3.3):
> error: conflicting declaration 'int Foo<T>::values [Foo::N]
> error: 'Foo<T>::values' has a previous declaration as 'int
> Foo<T>::values [Foo<T>::N]'
> error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
> class is not definition
>
> The compiler seems confused by the size because it accepts the code
> - if I replace the definition of N by:
> enum { N = T::size };
> - if I don't use N but T::size
>

There is no N in the template declration :
template<class T >

 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-24-2011
On 24 mar, 11:42, puppi <fabricio.pu...@gmail.com> wrote:
> On Mar 24, 6:18*am, Michael Doubez <michael.dou...@free.fr> wrote:
> > I have the following minimal code:

>
> > template< class T >
> > struct Foo {
> > * * static int const N = T::size;
> > * * static int values[N];};

>
> > template< class T > int const Foo<T>::N;
> > template< class T > int * * * * *Foo<T>::values[Foo<T>::N] = {};

>
> > struct Bar {
> > * * enum { size = 42 } ;

>
> > };

>
> > int main() {
> > * * Foo<Bar> f;
> > * * return f.N;

>
> > }

>
> > Which yield under gcc (4.1.3 and 4.3.3):
> > error: conflicting declaration 'int Foo<T>::values [Foo::N]
> > error: 'Foo<T>::values' has a previous declaration as 'int
> > Foo<T>::values [Foo<T>::N]'
> > error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
> > class is not definition

>
> > The compiler seems confused by the size because it accepts the code
> > * *- if I replace the definition of N by:
> > enum { N = T::size };
> > * - if I don't use N but T::size

>
> > This code pass under Comeau online (not in codepad).

>
> > Is this a compiler bug or is it expected behavior ?

>
> Well, under gcc 4.4.5 it compiles fine...


Ok. I suppose this is a bug and it has since been fixed.

> Have you tried to remove the declaration/initialization pair:
> template< class T > int const Foo<T>::N;
> template< class T > int Foo<T>::values[Foo<T>::N] = {};
> Since they really aren't necessary, trying to remove them would be my
> first try.


They are necessary.
Otherwise you get UB and if used, you are likely to get link errors.

--
Michael
 
Reply With Quote
 
Paul
Guest
Posts: n/a
 
      03-24-2011

"Michael Doubez" <> wrote in message
news:8ae3eed2-3be6-4fc1-b57f-...
On 24 mar, 11:42, puppi <fabricio.pu...@gmail.com> wrote:
> On Mar 24, 6:18 am, Michael Doubez <michael.dou...@free.fr> wrote:
> > I have the following minimal code:

>
> > template< class T >
> > struct Foo {
> > static int const N = T::size;
> > static int values[N];};

>
> > template< class T > int const Foo<T>::N;
> > template< class T > int Foo<T>::values[Foo<T>::N] = {};

>
> > struct Bar {
> > enum { size = 42 } ;

>
> > };

>
> > int main() {
> > Foo<Bar> f;
> > return f.N;

>
> > }

>
> > Which yield under gcc (4.1.3 and 4.3.3):
> > error: conflicting declaration 'int Foo<T>::values [Foo::N]
> > error: 'Foo<T>::values' has a previous declaration as 'int
> > Foo<T>::values [Foo<T>::N]'
> > error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
> > class is not definition

>
> > The compiler seems confused by the size because it accepts the code
> > - if I replace the definition of N by:
> > enum { N = T::size };
> > - if I don't use N but T::size

>
> > This code pass under Comeau online (not in codepad).

>
> > Is this a compiler bug or is it expected behavior ?

>
> Well, under gcc 4.4.5 it compiles fine...


Ok. I suppose this is a bug and it has since been fixed.

> Have you tried to remove the declaration/initialization pair:
> template< class T > int const Foo<T>::N;
> template< class T > int Foo<T>::values[Foo<T>::N] = {};
> Since they really aren't necessary, trying to remove them would be my
> first try.


They are necessary.
Otherwise you get UB and if used, you are likely to get link errors.
---------------------------------------------------------------------------

N is dependant on the template instanciation because:
static int const N = T::size. /*This does not instanciate the template.*/

The compiler cannot know what T::size refers to without a template
instanciation, so you need:
template< class T > int Foo<T>::values[Foo<T>::N]; /*Explicitly instaciate
the template*/
Note: afaik the ( ={} ) doesn't do anything and is not required.
ok now it knows that N is T::size:
static int values[N]; /* --- N is T::size. ---*/

AFAICT you do not need:
template< class T > int const Foo<T>::N; /* This is instanciated implicitly
with Foo<Bar> f anyway*/


HTH








 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-24-2011
On 24 mar, 19:07, "Paul" <pchris...@yahoo.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>
> news:8ae3eed2-3be6-4fc1-b57f-...
> On 24 mar, 11:42, puppi <fabricio.pu...@gmail.com> wrote:
>
>
>
>
>
>
>
>
>
> > On Mar 24, 6:18 am, Michael Doubez <michael.dou...@free.fr> wrote:
> > > I have the following minimal code:

>
> > > template< class T >
> > > struct Foo {
> > > static int const N = T::size;
> > > static int values[N];};

>
> > > template< class T > int const Foo<T>::N;
> > > template< class T > int Foo<T>::values[Foo<T>::N] = {};

>
> > > struct Bar {
> > > enum { size = 42 } ;

>
> > > };

>
> > > int main() {
> > > Foo<Bar> f;
> > > return f.N;

>
> > > }

>
> > > Which yield under gcc (4.1.3 and 4.3.3):
> > > error: conflicting declaration 'int Foo<T>::values [Foo::N]
> > > error: 'Foo<T>::values' has a previous declaration as 'int
> > > Foo<T>::values [Foo<T>::N]'
> > > error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
> > > class is not definition

>
> > > The compiler seems confused by the size because it accepts the code
> > > - if I replace the definition of N by:
> > > enum { N = T::size };
> > > - if I don't use N but T::size

>
> > > This code pass under Comeau online (not in codepad).

>
> > > Is this a compiler bug or is it expected behavior ?

>
> > Well, under gcc 4.4.5 it compiles fine...

>
> Ok. I suppose this is a bug and it has since been fixed.
>
> > Have you tried to remove the declaration/initialization pair:
> > template< class T > int const Foo<T>::N;
> > template< class T > int Foo<T>::values[Foo<T>::N] = {};
> > Since they really aren't necessary, trying to remove them would be my
> > first try.

>
> They are necessary.
> Otherwise you get UB and if used, you are likely to get link errors.
> ---------------------------------------------------------------------------
>
> N is dependant on the template instanciation


N is dependant on the template parameter.

> because:
> static int const N = T::size. /*This does not instanciate the template.*/


This declare a static member of integral type taking its value from
the template parameter.

>
> The compiler cannot *know what T::size refers to without a template
> instanciation, so you need:
> template< class T > int Foo<T>::values[Foo<T>::N]; */*Explicitly instaciate
> the template*/


It defines the static member. Nothing is instantiated.

The only work done by the compiler at this point is syntax checking.

> Note: afaik the ( ={} ) doesn't do anything and is not required.


It initialise the values of the array to the default value (0 in this
case).
You are right, it is not truly needed since global variable are 0
initialized by default; I use it out of habit.

> ok now it knows that N is T::size:
> static int values[N]; /* --- N is T::size. ---*/


That is the buggy step, the compiler doesn't recognize the definition
relatively to the declaration (irrelevantly of any instantiation).

> AFAICT you do not need:
> *template< class T > int const Foo<T>::N; /* This is instanciated implicitly
> with Foo<Bar> f anyway*/


No it is not implicity instanciated without a definition.
It is true that I don't really need it, provided I don't take a
reference to it: the compiler directly reuse the value specified at
declaration time; but it is formally UB.

--
Michael
 
Reply With Quote
 
Paul
Guest
Posts: n/a
 
      03-25-2011

"Michael Doubez" <> wrote in message
news:520c2341-2ef3-4f38-86df-...
On 24 mar, 19:07, "Paul" <pchris...@yahoo.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
> > > template< class T >
> > > struct Foo {
> > > static int const N = T::size;
> > > static int values[N];};

>
> > > template< class T > int const Foo<T>::N;
> > > template< class T > int Foo<T>::values[Foo<T>::N] = {};

>
> > > struct Bar {
> > > enum { size = 42 } ;

>
> > > };

>
> > > int main() {
> > > Foo<Bar> f;
> > > return f.N;

>
> > > }

>
> > > Which yield under gcc (4.1.3 and 4.3.3):
> > > error: conflicting declaration 'int Foo<T>::values [Foo::N]
> > > error: 'Foo<T>::values' has a previous declaration as 'int
> > > Foo<T>::values [Foo<T>::N]'
> > > error: declaration of 'int Foo<T>::values [Foo<T>::N]' outside of
> > > class is not definition

>
> > > The compiler seems confused by the size because it accepts the code
> > > - if I replace the definition of N by:
> > > enum { N = T::size };
> > > - if I don't use N but T::size

>
> > > This code pass under Comeau online (not in codepad).

>
> > > Is this a compiler bug or is it expected behavior ?

>
> > Well, under gcc 4.4.5 it compiles fine...

>
> Ok. I suppose this is a bug and it has since been fixed.
>
> > Have you tried to remove the declaration/initialization pair:
> > template< class T > int const Foo<T>::N;
> > template< class T > int Foo<T>::values[Foo<T>::N] = {};
> > Since they really aren't necessary, trying to remove them would be my
> > first try.

>
> They are necessary.
> Otherwise you get UB and if used, you are likely to get link errors.
> ---------------------------------------------------------------------------
>
> N is dependant on the template instanciation


--N is dependant on the template parameter.

> because:
> static int const N = T::size. /*This does not instanciate the template.*/


--This declare a static member of integral type taking its value from
--the template parameter.

Yes you are correct but the next occurence of N is not a template:
static int values[N];

I meant this cannot be resolved until the template is instanciated. But this
is all done by the compiler anyway. I was thinking about templates to much
and missed the obvious non-template issue.

template< class T >
struct Foo{
static int const N= T::size;
//static int values[N];
int arr[N];
};

The above would need exlicit instaciation if I was correct but it doesn't


>
> The compiler cannot know what T::size refers to without a template
> instanciation, so you need:
> template< class T > int Foo<T>::values[Foo<T>::N]; /*Explicitly instaciate
> the template*/


--It defines the static member. Nothing is instantiated.
Yes it defines the static.

--The only work done by the compiler at this point is syntax checking.
I disagree with that, I think the template must be instanciated, by the
compiler, to define N. But I'm not certain , I may be wrong.
I think there is more instanciations created under the hood than meets the
eye.


> Note: afaik the ( ={} ) doesn't do anything and is not required.


--It initialise the values of the array to the default value (0 in this
--case).
--You are right, it is not truly needed since global variable are 0
--initialized by default; I use it out of habit.

No I was wrong , I though the expression was an explicit template
instanciation and it isn't.
You are right this line defines the static array.


> ok now it knows that N is T::size:
> static int values[N]; /* --- N is T::size. ---*/


--That is the buggy step, the compiler doesn't recognize the definition
--relatively to the declaration (irrelevantly of any instantiation).

Yes I see how this can be a complex step for the compiler. I'm not sure how
a compiler implements this because it cannot know the value of N until is
has created a template instanciation, I think.


> AFAICT you do not need:
> template< class T > int const Foo<T>::N; /* This is instanciated
> implicitly
> with Foo<Bar> f anyway*/


--No it is not implicity instanciated without a definition.
--It is true that I don't really need it, provided I don't take a
--reference to it: the compiler directly reuse the value specified at
--declaration time; but it is formally UB.

How would taking a reference make any difference?

Does the template make any differenece to if you just did:
struct Foo{
static int const N = 42;
};


 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-25-2011
On 25 mar, 01:04, "Paul" <pchris...@yahoo.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
> On 24 mar, 19:07, "Paul" <pchris...@yahoo.co.uk> wrote:
> > AFAICT you do not need:
> > template< class T > int const Foo<T>::N; /* This is instanciated
> > implicitly
> > with Foo<Bar> f anyway*/

>
> --No it is not implicity instanciated without a definition.
> --It is true that I don't really need it, provided I don't take a
> --reference to it: the compiler directly reuse the value specified at
> --declaration time; but it is formally UB.
>
> How would taking a reference make any difference?
>
> Does the template make any differenece to if you just did:
> struct Foo{
> * * static int const N = 42;
> };


Try it out:
#include <iostream>

struct Foo
{
// link fails with this line
static int const N = 42;
// compiles with this line
// enum { N = 42 };
};


void print( int const & v ) {
std::cout<<v<<'\n';
}

int main() {
print(Foo::N);
}

--
Michael
 
Reply With Quote
 
Paul
Guest
Posts: n/a
 
      03-25-2011

"Michael Doubez" <> wrote in message
news:52efd416-36f1-4a58-9781-...
>On 25 mar, 01:04, "Paul" <pchris...@yahoo.co.uk> wrote:
>> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>> On 24 mar, 19:07, "Paul" <pchris...@yahoo.co.uk> wrote:
>> > AFAICT you do not need:
>> > template< class T > int const Foo<T>::N; /* This is instanciated
>> > implicitly
>> > with Foo<Bar> f anyway*/

>>
>> --No it is not implicity instanciated without a definition.
>> --It is true that I don't really need it, provided I don't take a
>> --reference to it: the compiler directly reuse the value specified at
>> --declaration time; but it is formally UB.
>>
>> How would taking a reference make any difference?
>>
>> Does the template make any differenece to if you just did:
>> struct Foo{
>> static int const N = 42;
>> };

>
>Try it out:
>#include <iostream>
>struct Foo{
> // link fails with this line
> static int const N = 42;
> // compiles with this line
> // enum { N = 42 };
>};
>
>void print( int const & v ) { std::cout<<v<<'\n';}
>
>int main() {
> print(Foo::N);
>}


I did try it out after I posted, and it worked just fine, what compiler did
you say to avoid again?
Here's the code I posted , maybe that compile of yours isn't too good.

struct Bar1 { enum { size = 42 } ;};
struct Bar2 { enum { size = 52 } ;};

template< class T >
struct Foo{
static int const N= T::size;
static int values[N];
public:
Foo(){}
template<typename U>
void func(Foo<U>& para);
};

//template< class T > int const Foo<T>::N;
template<class T> int Foo<T>::values[Foo<T>::N]={0};

template<typename T>
template<typename U>
void Foo<T>::func(Foo<U>& para){
std::cout<< "\nthis->N: \t" << this->N;
std::cout<< "\nthat.N: \t" << para.N;
}

void funct(int const & r){
std::cout<<"\nIn funct, value of parameter = " << r;
}

int main() {
Foo<Bar1> f1;
Foo<Bar2> f2;

funct(f1.N);
funct(f2.N);
f1.func(f2);
f2.func(f1);
}


I also tried another couple of ways to use it as a reference and all seemed
to compile ok with Microsoft v14 command line compiler.

And I don't think that version is too good because i have had problems with
it compiling templates in the form of :
template<template<class T> class U, classT>
When I go onto my newer VS2010 these compile just fine , so that old command
line compiler I've been using to test your code isn't the greatest but it
seems to compile/link your code fine without
template< class T > int const Foo<T>::N;


HTH





 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-25-2011
On 25 mar, 11:07, "Paul" <pchris...@yahoo.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
> >On 25 mar, 01:04, "Paul" <pchris...@yahoo.co.uk> wrote:
> >> "Michael Doubez" <michael.dou...@free.fr> wrote in message
> >> On 24 mar, 19:07, "Paul" <pchris...@yahoo.co.uk> wrote:
> >> > AFAICT you do not need:
> >> > template< class T > int const Foo<T>::N; /* This is instanciated
> >> > implicitly
> >> > with Foo<Bar> f anyway*/

>
> >> --No it is not implicity instanciated without a definition.
> >> --It is true that I don't really need it, provided I don't take a
> >> --reference to it: the compiler directly reuse the value specified at
> >> --declaration time; but it is formally UB.

>
> >> How would taking a reference make any difference?

>
> >> Does the template make any differenece to if you just did:
> >> struct Foo{
> >> static int const N = 42;
> >> };

>
> >Try it out:
> >#include <iostream>
> >struct Foo{
> > * *// link fails with this line
> > * *static int const N = 42;
> > * *// compiles with this line
> > * *// enum { N = 42 };
> >};

>
> >void print( int const & v ) { std::cout<<v<<'\n';}

>
> >int main() {
> > * *print(Foo::N);
> >}

>
> I did try it out after I posted, and it worked just fine, what compiler did
> you say to avoid again? *

[snip]
> When I go onto my newer VS2010 these compile just fine , so that old command
> line compiler I've been using to test your code isn't the greatest but it
> seems to compile/link your code fine without
> template< class T > int const Foo<T>::N;


It doesn't compile on codepad (And comeau doesn't link so it is of no
help here).
It doesn't either on gcc (up to 4.3.3)

The standard is quite clear on the subject with the one definition
rule and a static data member is always a declaration within the class
scope (§9.4.2/2)
"The declaration of a /static/ data member in its class is not a
definition [...].

And more precisely §9.4.2/4:
"If a static data member is of const integral or const enumeration
type, its declaration in the class
definition can specify a constant-initializer which shall be an
integral constant expression (5.19). In that
case, the member can appear in integral constant expressions. *The
member shall still be defined in a namespace scope if it is used in
the program* and the namespace scope definition shall not contain an
initializer."

This requirement still holds in the proposal for c++0x.

It may be a compiler extension or perhaps they don't consider this as
"used in the program" (the value is used but not the variable, it
could make sense).

--
Michael
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
conflicting types or implicit declaration or incompatible implicitdeclaration dentzigui C Programming 8 11-01-2009 03:07 AM
previous declaration of Table was here / conflicting types for Michael.Z C Programming 11 05-11-2008 03:11 AM
Can a static member function access non-static member? dolphin C++ 3 12-05-2007 12:39 PM
Can a static function declaration conflict with a non-static declaration? nospam_timur@tabi.org C Programming 4 12-12-2006 10:26 PM
conflicting declaration for iostream, namespace conflict? humble04@gmail.com C++ 2 12-29-2004 02:39 PM



Advertisments