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

Isn't 'std:.string::npos' an integral constant?

P: n/a
Hi,

this
#include <string>
class test {
typedef std::string::size_type size_type;
static const size_type x = std::string::npos;
};
doesn't compile using either VC9 ("expected constant expression")
or Comeau Online ("constant value is not known"). If I replace
'std::string::npos' by '-1' it compiles.
Why isn't 'std::string;::npos' a "known constant expression"? What
am I missing?

TIA;

Schobi
Sep 19 '08 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Hendrik Schober wrote:
this
#include <string>
class test {
typedef std::string::size_type size_type;
static const size_type x = std::string::npos;
};
doesn't compile using either VC9 ("expected constant expression")
or Comeau Online ("constant value is not known"). If I replace
'std::string::npos' by '-1' it compiles.
Why isn't 'std::string;::npos' a "known constant expression"? What
am I missing?
Hard to say. AFAICT, 14.7.1/1 requirements are met, the static data
member 'npos' should be instantiated (and the definition should exist),
and since 'npos' itself was initialised with a const expression, it is
allowed to be used in another const expression (5.19/1). Seems like a
bug in both compilers.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 19 '08 #2

P: n/a
Hendrik Schober <sp******@gmx.dekirjutas:
Hi,

this
#include <string>
class test {
typedef std::string::size_type size_type;
static const size_type x = std::string::npos;
};
doesn't compile using either VC9 ("expected constant expression")
or Comeau Online ("constant value is not known"). If I replace
'std::string::npos' by '-1' it compiles.
Why isn't 'std::string;::npos' a "known constant expression"? What
am I missing?
Integral const expressions are usuful mostly for declaring C-style array
sizes and for template specialization. Most probably you never want to
declare an array of std::string::npos elements. OTOH, it may be imaginable
that you want to specialize a template with that value, but I guess this
was not considered a sufficiently sound reason to require std::string::npos
to be a const expression.

Paavo

Sep 22 '08 #3

P: n/a
James Kanze wrote:
On Sep 20, 8:56 pm, Hendrik Schober <spamt...@gmx.dewrote:
[...]
> For one, there's 5.19 which says:
"An integral constant expression can involve [...]
static data members of integral or enumeration types
[...]."
So it seems that a static data member of integral type
is a constant integral expression.

Not necessarily. You cut part of the requirements. The
essential parts read "An integral constant expression can
involve [...]const variables or static data members of integral
or enumeration types initialized with constant
expressions,[...]" It's quite clear that the "or" between
"variables" and "static data members" joins just those two
nominal groups; that everything else (const, initialized with
constant expressions) applies to both. [...]
(Is it? Well, did I say I dread having to read the standard?)
> Then there's 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)."
The way I read this, my 'test::x', which is of integral
type, can be initialized in-class, if I use a constant
integral expression.

It can be. Yes.
> Finally, 21.3 shows 'std::basic_string<T>::npos' as
static const size_type npos = -1;
(which is the only thing I was able to find resembling
a definition of what it should be).

And this is where it is unclear. How significant is the fact
that the value is given in this format? It is obvious that the
standard doesn't require textual identity with its class
definitions, but just what does it require? [...]
It doesn't? I would have thought it does.
> To me this looks like 'std::string::npos' is defined as
being '-1', which would make it an integral constant
definition, which in turn means it could be used to
initialize constant static data member of integral type.
Which I thought I tried to do.
> I'm sure I missed something along the way (for example,
I have no idea what 14.7.1 has to do with all this), but
I wouldn't know what.

The real question is whether the initializer of npos is visible
when you want to use it as an integral constant expression. I
would sort of expect it to be in most implementations, because
this seems like the simplest way of doing it. But I'm far from
sure that it is required.
In VC9's implementation (Dinkumware), 'npos' is initialized
after the class template's definition. But so it was in VC71
(Dinkumware, too), where th same code used to compile...

Anyway, thanks for taking the time to explain.

Schobi
Sep 22 '08 #4

P: n/a
Paavo Helde wrote:
Hendrik Schober <sp******@gmx.dekirjutas:
>Hi,

this
#include <string>
class test {
typedef std::string::size_type size_type;
static const size_type x = std::string::npos;
};
doesn't compile using either VC9 ("expected constant expression")
or Comeau Online ("constant value is not known"). If I replace
'std::string::npos' by '-1' it compiles.
Why isn't 'std::string;::npos' a "known constant expression"? What
am I missing?

Integral const expressions are usuful mostly for declaring C-style array
sizes and for template specialization. Most probably you never want to
declare an array of std::string::npos elements. OTOH, it may be imaginable
that you want to specialize a template with that value, but I guess this
was not considered a sufficiently sound reason to require std::string::npos
to be a const expression.
In my case it was some open source lib which, for reasons I haven't
looked into, introduced its own string class while depending on
'std::string' to supply its 'npos' value...
Paavo
Schobi
Sep 22 '08 #5

P: n/a
On Sep 22, 11:50 pm, Paavo Helde <nob...@ebi.eewrote:
Hendrik Schober <spamt...@gmx.dekirjutas:
Interestingly, Comeau compile this
struct test1 {
static const int x = -1;
};
struct test2 {
static const int x = test1::x;
};
without any complaints. However, it compiles this
struct test1 {
static const int x;
};
const int test1::x = 1;
struct test2 {
static const int x = test1::x;
};
just as well.
Indeed. However, if test1 is a template, it fails. Seems a bit
inconsistent.
Not really. A template definition is not a variable definition;
only the instantiation of a template definition is a variable
definition. And the "point of instantiation" of a member
function or member static variable is immediately following the
namespace scope declaration which triggers the instantiation.
So if you write:

template< typename T >
struct test1
{
static int const x ;
} ;

template< typename T >
int const test1::x = 1 ;

struct test2
{
static int const x = test1< int >::x ;
} ;

, the compiler inserts the instantiation of the class test1<int>
immediately before the definition of test2, and the
instantiation of the static data member immediately after, i.e.:

struct test1< int >
{
static int const x ;
} ;

struct test2
{
static int const x = test1< int >::x ;
} ;
int const test1< int >::x = 1 ;

And the value of test1< int >::x isn't visible when test2::x is
declared.

--
James Kanze (GABI Software) email:ja*********@gmail.com
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
Sep 23 '08 #6

P: n/a
On 2008-09-23 03:45:08 -0400, James Kanze <ja*********@gmail.comsaid:
>
Out of curiousity, I generated the preprocessor output for a
program consisting of just an #include <string>, for all of the
compiler/library combinations I have available. None seem to
have an explicit specialization. They split with regards to
where npos is initialized, with those that initialize it in the
class never providing a declaration (which results in undefined
behavior if you use it in a context where the object is
required---but compilers can defined undefined behavior).
And the implementation of the standard library does not have to be
written in portable C++, something which even members of the standards
committee have to be reminded of.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Sep 23 '08 #7

P: n/a
On Sep 23, 2:20 pm, Pete Becker <p...@versatilecoding.comwrote:
On 2008-09-23 03:45:08 -0400, James Kanze <james.ka...@gmail.comsaid:
Out of curiousity, I generated the preprocessor output for a
program consisting of just an #include <string>, for all of
the compiler/library combinations I have available. None
seem to have an explicit specialization. They split with
regards to where npos is initialized, with those that
initialize it in the class never providing a declaration
(which results in undefined behavior if you use it in a
context where the object is required---but compilers can
defined undefined behavior).
And the implementation of the standard library does not have
to be written in portable C++, something which even members of
the standards committee have to be reminded of.
That was more or less what I meant to imply with my comment in
parentheses. In this case, the implementation of
std::basic_string in the g++ library clearly contains undefined
behavior, according to the standard. But it works with g++,
because of what the compiler does in this particular case, and
that's all that matters; it's not an error in the library.

--
James Kanze (GABI Software) email:ja*********@gmail.com
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
Sep 23 '08 #8

This discussion thread is closed

Replies have been disabled for this discussion.