Constness Complications

J

JKop

Here's two functions, a "const version" and a "non-const version":


char* GetFirstT(char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

signed main()
{
char the_alphabet[] = "abcdefghijklmnopqrstuvwxyz";

char* p_t = GetFirstT(the_alphabet);
}


See how I have to define two functions, is there any handy around that?
Would I have to do the following:

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

char* GetFirstT(char* p)
{
return const_cast<char*>( GetFirstT(p) );
}


-JKop
 
B

bartek

JKop said:
Here's two functions, a "const version" and a "non-const version":


char* GetFirstT(char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

signed main()
{
char the_alphabet[] = "abcdefghijklmnopqrstuvwxyz";

char* p_t = GetFirstT(the_alphabet);
}


See how I have to define two functions, is there any handy around that?

No, you dont need to define both of them. See below.

#include <iostream>

char const* get_first_of(char const* s, char c)
{
for (; *s && *s != c; ++s);
return s;
}

int main()
{
char s[] = "abcdefghijklmnopqrstuvwxyz";
const char cs[] = "abcdefghijklmnopqrstuvwxyz";

const char* p1 = get_first_of(s, 'c');
const char* p2 = get_first_of(cs, 't');

std::cout << p1 << '\n'
<< p2 << '\n';

return 0;
}

When a function specifies its argument as const, it clearly means that it
won't modify that. Const-specifier can be implicitly hooked on.

Cheers.
 
?

=?ISO-8859-1?Q?Tobias_G=FCntner?=

JKop said:
See how I have to define two functions, is there any handy around that?
Would I have to do the following:

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

char* GetFirstT(char* p)
{
return const_cast<char*>( GetFirstT(p) );
}

Why don't you use templates?

template<typename CHARTYPE>
CHARTYPE* GetFirstT(CHARTYPE* p)
{
....
}
 
A

AlesD

JKop said:
Here's two functions, a "const version" and a "non-const version":


char* GetFirstT(char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

signed main()
{
char the_alphabet[] = "abcdefghijklmnopqrstuvwxyz";

char* p_t = GetFirstT(the_alphabet);
}


See how I have to define two functions, is there any handy around that?
Would I have to do the following:

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}

return 0;
}

char* GetFirstT(char* p)
{
return const_cast<char*>( GetFirstT(p) );
}


-JKop

Hello,

what about using template?

template <class charT>
charT* GetFirstT(charT* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}
return 0;
}

signed main()
{
char the_alphabet[] = "abcdefghijklmnopqrstuvwxyz";

char* p_t = GetFirstT<char>(the_alphabet);
}

This way you can create GetFirstT() even for wchar and const wchar. Even
better would force use of character_traits, but this is too much for me.
Maybe someone else will know...

Ales
 
P

Pete Becker

AlesD said:
Hello,

what about using template?

Templates aren't appropriate here.
template <class charT>
charT* GetFirstT(charT* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}
return 0;
}

signed main()
{
char the_alphabet[] = "abcdefghijklmnopqrstuvwxyz";

char* p_t = GetFirstT<char>(the_alphabet);
}

This way you can create GetFirstT() even for wchar and const wchar.

Well, you'd get code that compiles and runs. But what does *p == 't'
tell you when the type of p is wchar_t*? There is no requirement that
L't' == 't'.
 
J

JKop

Tobias Güntner posted:
Why don't you use templates?

template<typename CHARTYPE>
CHARTYPE* GetFirstT(CHARTYPE* p)
{
...
}


That template is non-const.


-JKop
 
J

JKop

Just to elaborate more on that. While this function doesn't edit any
objects; if possible I want to be able to return a non-const pointer, as the
user may want to then use it for something.

I'm looking for using the same body of code for multiple functions. Like
imagine something like this:

body Blah
{
//code
}

char* FuncName(char*)
using body Blah;

const char* FunctName2(const char*)
using body Blah;


Looks like I've only got two options: either copy and paste and actually
make two functions. The only pickle I have with this is maintaining two
functions, plus added compile time.

Who here would go with the const_cast version?


-JKop

-JKop
 
D

David Hilsee

I'm looking for using the same body of code for multiple functions. Like
imagine something like this:

body Blah
{
//code
}

char* FuncName(char*)
using body Blah;

const char* FunctName2(const char*)
using body Blah;


Looks like I've only got two options: either copy and paste and actually
make two functions. The only pickle I have with this is maintaining two
functions, plus added compile time.

Who here would go with the const_cast version?

I've done it before, and I would do it again. I don't know of anything that
would cause problems when using that technique.
 
B

bartek

JKop said:
Just to elaborate more on that. While this function doesn't edit any
objects; if possible I want to be able to return a non-const pointer,
as the user may want to then use it for something.

Then you should provide a non-const copy of the object in question, so
there would be no risk of blowing things up.

'const' is there to help keep programs correct. Either use it, or lose it.
 
?

=?ISO-8859-1?Q?Tobias_G=FCntner?=

JKop said:
Tobias Güntner posted:



That template is non-const.

CHARTYPE can be 'char' or 'const char', depending on the parameter type.
 
O

Old Wolf

JKop said:
Here's two functions, a "const version" and a "non-const version":

char* GetFirstT(char* p)
{
for ( ; *p; ++p)
if ( *p == 't' ) return p;
return 0;
}

const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
if ( *p == 't' ) return p;
return 0;
}
See how I have to define two functions, is there any handy around that?

The C standard library solves this problem with:

char *strchr(const char *ptr, char ch);

ie. using 'const' in the parameter and non-const in the return type.
This 'minimises the damage', ie. you only have to use casts
(when calling the function I mean, not when implementing it) if
you use it on a const string and assign the result to a 'const char *'.

But since this is C++ we can use a template:

template<typename Iter>
Iter GetFirstT(Iter p)
{
for ( ; ; ++p )
if (*p == 't' || *p == '\0')
return p;
}

Constraints - 'Iter' must be a type for which '++', '==' with a char,
and '*' are valid operations.

Note that I have made a slight change, it returns a pointer to the end
of the string instead of NULL if the 't' is not found. But you could
easily stick to your version, but add the constraint that 'Iter'
must be such that it can have 0 assigned to it.

There have been a couple of objections to this approach raised in
this thread, which I don't understand...

You said "the template is non-const". But it does not make sense
to say that a template is const or not, so I have no idea what you
meant. Are you unaware that you can have GetFirstT<char *> and
GetFirstT<char const *> ?

Pete Becker said "GetFirstT<wchar_t *>" doesn't work. So what?
The original stipulation was only for "char *" and "char const *",
and this example does just fine for them. There are plenty
of examples in the standard library where templates won't work
if you use the wrong types as parameters.
 
J

JKop

Tobias Güntner posted:
CHARTYPE can be 'char' or 'const char', depending on the parameter type.

No it cannot. CHARTYPE refers to the 'char'.

For a const template:

template<class T>
void Blah(const T)
{

}


-JKop
 
?

=?ISO-8859-1?Q?Tobias_G=FCntner?=

JKop said:
parameter type.


No it cannot.

Yes, it can.
What makes you think it cannot?
CHARTYPE refers to the 'char'.

CHARTYPE refers to the type the pointer points to. That can be anything,
including const chars.
For a const template:

template<class T>
void Blah(const T)

Now why would you want this one? If you pass a char* here, you have a
const pointer to non-const chars, i.e. you cannot alter the pointer.
 
J

JKop

Tobias Güntner posted:
Yes, it can.
What makes you think it cannot?


CHARTYPE refers to the type the pointer points to. That can be anything,
including const chars.


Now why would you want this one? If you pass a char* here, you have a
const pointer to non-const chars, i.e. you cannot alter the pointer.

You're right.

But still I want to restrict it to either being char* or
const char*.


-JKop
 
D

David Rubin

JKop said:
Here's two functions, a "const version" and a "non-const version":

[snip - two similar implementations]
const char* GetFirstT(const char* p)
{
for ( ; *p; ++p)
{
if ( *p == 't' ) return p;
}
return 0;
}
char* GetFirstT(char* p)
{
return const_cast<char*>( GetFirstT(p) );
}

This is reasonable, especially if the second is inlined and the first
is not. However, it doesn't make a lot of sense that you would have a
non-const version of this particular function.

/david
 

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,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top