By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,389 Members | 1,881 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,389 IT Pros & Developers. It's quick & easy.

Difference between inline initialization and definition.

P: n/a

I posted a gcc bug

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13332
here is the text:
-----------------------------------------------------------

This code will compile fine but fail on a linker error.

templ_examp.cpp:41: undefined reference to `Bounds<float,
(unsigned)4>::size'

However if "static const unsigned size" is changed from an "unsigned" to an
"int" or "short", it appears to work correctly.
template <typename T, unsigned N>
class Bounds
{
public:

static const unsigned size = N;
T * ptr;

T & operator[] ( unsigned i )
{
if ( i >= size )
{
throw "Array outa bounds";
}

return ptr[ i ];
}

Bounds( T ( & i_ptr)[N] )
: ptr( i_ptr )
{
}
};

template <typename T, unsigned N>
Bounds<T,N> make_bounds( T ( & i_ptr)[N] )
{
return Bounds<T,N>( i_ptr );
}
float array[] = { 1., 2., 3., 4. };

#include <iostream>

int main()
{

std::cout << make_bounds( array )[ 2 ];
std::cout << make_bounds( array ).size;
// std::cout << make_bounds( array )[ 20 ]; // throw exception
}
------- Additional Comment #1 From Andrew Pinski 2003-12-06 08:18
[reply] -------

From bug 13259 which this is bug is a dup of:
The standard says that you may inline-initialize the static variable,
but you still need to _define_ it somewhere so that a memory location
is assigned to it.

-----------------------------------------------------------

if below is not a definition:

....
static const unsigned size = N;
....

what is it ?

Jul 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Gianni Mariani wrote in news:bq********@dispatch.concentric.net:

I posted a gcc bug

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13332
here is the text:
-----------------------------------------------------------

This code will compile fine but fail on a linker error.

templ_examp.cpp:41: undefined reference to `Bounds<float,
(unsigned)4>::size'

However if "static const unsigned size" is changed from an "unsigned"
to an "int" or "short", it appears to work correctly.

Actually it works inspite of the fact your code is incorrect. I can't
remember wether a compiler is required to produce a diagnostic (an
error / warning meassage) when this rule is violated, but I think not.

template <typename T, unsigned N>
class Bounds
{
public:

static const unsigned size = N;
T * ptr;

T & operator[] ( unsigned i )
{
This usage of 'size' is not one where a compile-time constant is
required. (see below).

Note that when you change size to int or short, the comparison below
requires a conversion from (int or short) to unsigned. It would appear
that gcc "thinks" its easier to do this by converting the initializer (N)
directly (hence no linking). When size is unsigned gcc "thinks" a memory
reference would be better, so the linker discovers your incorrect code.

if ( i >= size )
{
throw "Array outa bounds";
}

return ptr[ i ];
}

Bounds( T ( & i_ptr)[N] )
: ptr( i_ptr )
{
}
};

template <typename T, unsigned N>
Bounds<T,N> make_bounds( T ( & i_ptr)[N] )
{
return Bounds<T,N>( i_ptr );
}
float array[] = { 1., 2., 3., 4. };

#include <iostream>

int main()
{

std::cout << make_bounds( array )[ 2 ];
std::cout << make_bounds( array ).size;
// std::cout << make_bounds( array )[ 20 ]; // throw exception
}
------- Additional Comment #1 From Andrew Pinski 2003-12-06 08:18
[reply] -------

From bug 13259 which this is bug is a dup of:
The standard says that you may inline-initialize the static variable,
but you still need to _define_ it somewhere so that a memory location
is assigned to it.

In other words it isn't a bug (in gcc).
-----------------------------------------------------------

if below is not a definition:

...
static const unsigned size = N;
...

what is it ?


Its a declaration and an intialization, but it is not a *definition*.

The value of this initialization can only be used where a compile-time
contexts is *required*, i.e. as an array bounds, as a template paramiter
etc. Otherwise a defenition is required.

The defenition should be like this:

template <typename T, unsigned N>
unsigned const Bounds< T, N >::size; /* no initializer */

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #2

P: n/a
Rob Williscroft wrote:
Gianni Mariani wrote in news:bq********@dispatch.concentric.net:
Its a declaration and an intialization, but it is not a *definition*.

The value of this initialization can only be used where a compile-time
contexts is *required*, i.e. as an array bounds, as a template paramiter
etc. Otherwise a defenition is required.

The defenition should be like this:

template <typename T, unsigned N>
unsigned const Bounds< T, N >::size; /* no initializer */


OK, I get it. Thanks for clearing that up.

However, I still don't get the reason for this. Is there a good reason
to be splitting hairs like this ? After all, the compiler can certainly
work out when a reference is needed or not. If it was uninitiialized, I
can imagine why one should have a declaration, but is seems very strange
to be able to initialize a variable an not declare it.

With C++, you learn somthing every day :-)

Jul 22 '05 #3

P: n/a
Gianni Mariani wrote in news:bq********@dispatch.concentric.net:
Rob Williscroft wrote:
Gianni Mariani wrote in news:bq********@dispatch.concentric.net:

Its a declaration and an intialization, but it is not a *definition*.

The value of this initialization can only be used where a
compile-time contexts is *required*, i.e. as an array bounds, as a
template paramiter etc. Otherwise a defenition is required.

The defenition should be like this:

template <typename T, unsigned N>
unsigned const Bounds< T, N >::size; /* no initializer */


OK, I get it. Thanks for clearing that up.

However, I still don't get the reason for this. Is there a good
reason to be splitting hairs like this ?


Not that I'm aware off, particularly as templates get "merged" all the
time.

The /bad/ reason is probably the comittee though 1 exception for
static integral constants was enough.
After all, the compiler can
certainly work out when a reference is needed or not. If it was
uninitiialized, I can imagine why one should have a declaration, but
is seems very strange to be able to initialize a variable an not
declare it.

With C++, you learn somthing every day :-)


Yup.

I thought of this workaround (assuming there's some good reason
for avoiding the *definition*), since you don't need a definition
if you avoid all non-compile-time contexts.

template < unsigned N > class whatever
{
static unsigned const size = N;
....
....
if (i < sizeof( char[ size ] )) ...

or:

....
enum {Size = size};
if (i < Size) ...
Maybe a member function would be better though:

static unsigned runtime_size()
{
return unsigned( sizeof( char[ size ] ));
}

Rob. -- http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #4

P: n/a
Rob Williscroft wrote:
Gianni Mariani wrote in news:bq********@dispatch.concentric.net: I thought of this workaround (assuming there's some good reason
for avoiding the *definition*), since you don't need a definition
if you avoid all non-compile-time contexts.

template < unsigned N > class whatever
{
static unsigned const size = N;
...
...
if (i < sizeof( char[ size ] )) ...

or:

...
enum {Size = size};
if (i < Size) ...
Maybe a member function would be better though:

static unsigned runtime_size()
{
return unsigned( sizeof( char[ size ] ));
}


This is cool ...

In this particular case though you could more simply write "return N".

I'm not too concerned about having to add a declaration, I'm more
concerned about the apparent violation of the "rule of least astonishment".


Jul 22 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.