Topic: Ambiguity/redundancy in basic_string


Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 3 Jun 2004 21:31:02 +0000 (UTC)
Raw View
kprateek88@yahoo.com (Prateek R Karandikar) wrote in message news:<607f883e.0406020620.10e20dd7@posting.google.com>...
> I've understood that the standard requires CharT, Traits::char_type,
> and Allocator::value_type to be the same. But, as I asked in my first
> post: why this redundancy? What happens when they are not the same? Is

The standard does not define what happens when they are not the same.
This means that an implementation is allowed to contain code that
assumes that they are the same, and which therefore breaks in whatever
fashion such code would be expected to break, if they aren't. There's
an awful lot of different ways to build that assumption into the code,
and an even larger number of different ways in which it can break. I
wouldn't recommend making any assumptions about what can happen.

> it undefined? If yes, then an error which theoreticaly can be caught
> at compile-time ( whether the types are same or not is known at
> compile-time) leads to undefined behaviour. Isn't there some way to
> give a compile error?.

A diagnostic message is required for all diagnoseable errors(1.4p2).
This one looks diagnoseable to me.

> Why not just do:
>
> template<typename Ch, typename Tr=char_traits<Ch>, typename A =
> alloctor<Ch> >
> class basic_string
> {
>  //...
>  public:
>  typedef Ch value_type;
>  //...
> };
>
> Thus we would never need to use Tr::char_type or A::value_type.

I don't think it matters. As long as we retain a requirement that all
three types be the same, it doesn't make much difference which one is
used. If that requirement were removed, it would make implementation a
lot more complicated.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Fri, 28 May 2004 02:00:01 +0000 (UTC)
Raw View
tom_usenet@hotmail.com (tom_usenet) wrote in message news:<4fd9b0994kso2n0kavq4jkcn7a0bv4qljr@4ax.com>...
..
> I think the OP is proposing:
>
> template <
>   class Traits = std::char_traits<char>,
>   class Alloc = std::allocator<typename Traits::char_type>
> >
> class basic_string;
>
> typedef basic_string<char_traits<char> > string;
> typedef basic_string<char_traits<wchar_t> > wstring;
>
> And he's got a point - the charT template parameter is completely
> redundant as far as I can tell.

Not it's not. Because the first template parameter is CharT, it can be
implicitly deduced from member function arguments that depend upon
CharT, removing the need to specify it explicitly. I've found three
cases where that matters: when building temporaries using either the
constructor that uses a CharT* argument or the constructor that uses a
count combined with a single CharT argument, and when callign the
static member function to_int_type(). There may be other cases I
haven't thought of.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: tom_usenet <tom_usenet@hotmail.com>
Date: Fri, 28 May 2004 10:39:04 CST
Raw View
On Fri, 28 May 2004 02:00:01 +0000 (UTC), kuyper@wizard.net (James
Kuyper) wrote:

>> And he's got a point - the charT template parameter is completely
>> redundant as far as I can tell.
>
>Not it's not. Because the first template parameter is CharT, it can be
>implicitly deduced from member function arguments that depend upon
>CharT, removing the need to specify it explicitly.

Member functions of what? basic_string? But then you already know the
template arguments.

 I've found three
>cases where that matters: when building temporaries using either the
>constructor that uses a CharT* argument or the constructor that uses a
>count combined with a single CharT argument, and when callign the
>static member function to_int_type(). There may be other cases I
>haven't thought of.

to_int_type isn't a template function - I wasn't suggesting changing
char_traits at all (it would still be a template taking one charT
parameter). So I don't see what you mean. Why would you ever need to
explicitly specify the char_type - you've already got a traits object
which knows its own char_type. As for creating temporaries, that's
already a problem. e.g.

template <class CharT>
void g(std::basic_string<CharT> const& s)
{
}

g("foo"); //error!

You'll have to explain what you mean with some code. I think you may
have misread my previous code. I proposed removing the charT template
parameter, but keeping the other two as-is. e.g.

template <
  class Traits,
  class Alloc = std::allocator<typename Traits::char_type>
>
class basic_string
{
public:
  typedef typename Traits::char_type char_type;

  basic_string(char_type const* p);
  //...
};

There may be some problems relating to template argument deduction,
but I can't think of any at the moment.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kprateek88@yahoo.com (Prateek R Karandikar)
Date: Wed, 2 Jun 2004 15:11:50 +0000 (UTC)
Raw View
I've understood that the standard requires CharT, Traits::char_type,
and Allocator::value_type to be the same. But, as I asked in my first
post: why this redundancy? What happens when they are not the same? Is
it undefined? If yes, then an error which theoreticaly can be caught
at compile-time ( whether the types are same or not is known at
compile-time) leads to undefined behaviour. Isn't there some way to
give a compile error?.

Why not just do:

template<typename Ch, typename Tr=char_traits<Ch>, typename A =
alloctor<Ch> >
class basic_string
{
 //...
 public:
 typedef Ch value_type;
 //...
};

Thus we would never need to use Tr::char_type or A::value_type.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: tom_usenet@hotmail.com (tom_usenet)
Date: Wed, 26 May 2004 16:18:44 +0000 (UTC)
Raw View
On Tue, 25 May 2004 16:12:32 +0000 (UTC), kuyper@wizard.net (James
Kuyper) wrote:

>The current design allows the traits class to not be a template, but
>simply a single class that have a fixed typedef for char_type. I'm not
>sure how important this aspect of the design is, but I'm sure that by
>now someone, perhaps many people, has written code that depends upon
>it. Hence, more backwards compatibility problems.

I think the OP is proposing:

template <
  class Traits = std::char_traits<char>,
  class Alloc = std::allocator<typename Traits::char_type>
>
class basic_string;

typedef basic_string<char_traits<char> > string;
typedef basic_string<char_traits<wchar_t> > wstring;

And he's got a point - the charT template parameter is completely
redundant as far as I can tell.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kprateek88@yahoo.com (Prateek R Karandikar)
Date: Tue, 25 May 2004 05:55:14 +0000 (UTC)
Raw View
template<typename Ch, typename Tr = std::char_traits<Ch>, typename A =
std::allocator<Ch> >
class std::basic_string
{
  //..
 public:
  typedef typename Tr::char_type value_type;
  //...
};

In general, the type Ch may not be the same as the type typename
Tr::char_type. Is there a requirement that these two be the same types? If
yes, why this redundancy? If not, why this ambiguity?

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
To iterate is human, to recurse divine.
-L. Peter Deutsch
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dsp@bdal.de (=?ISO-8859-1?Q?=22Daniel_Kr=FCgler_=28ne_Spangenberg=29=22?=)
Date: Tue, 25 May 2004 16:11:59 +0000 (UTC)
Raw View
Good morning,  Prateek R Karandikar

Prateek R Karandikar schrieb:

>template<typename Ch, typename Tr =3D std::char_traits<Ch>, typename A =3D=
=20
>std::allocator<Ch> >
>class std::basic_string
>{
>  //..
> public:
>  typedef typename Tr::char_type value_type;
>  //...
>};
>
>In general, the type Ch may not be the same as the type typename=20
>Tr::char_type. Is there a requirement that these two be the same types? =
If=20
>yes, why this redundancy? If not, why this ambiguity?
> =20
>

Both are the same. First consider the standard itself, The class=20
template interface from 21.3 is binding:

namespace std {
template<class charT, class traits =3D char_traits<charT>,
class Allocator =3D allocator<charT> >
class basic_string {
public:
// types:
typedef traits traits_type;
typedef typename traits::char_type value_type;
..
};

There do exist two further guarantees which provide cyclic consistency:

- 21.1/p.3:
"To specialize those templates to generate a string or iostream class to=20
handle a particular character
container type CharT, that and its related character traits class Traits=20
are passed as a pair of
parameters to the string or iostream template as formal parameters charT=20
and traits. Traits::char_type
shall be the same as CharT."

This ensures, that the template parameter Ch from the std::basic_string=20
class template is synchronized
with the also provided traits template parameter (which is demanded to=20
provide a char_type typename
fulfilling the above described requirements).

- The interface description from 21.3 demands that traits::char_type is=20
the same as value_type. Note
that this description is binding.

Last but not least (although not directly related to the discussed=20
problem), it is also guaranteed, that
basic_string's allocator class fulfills the following (from 21.3/p.1):

"[..] Allocator::value_type shall be the same as charT."

The reason for the additional value_type typename from the basic_string=20
class template is to align
with the container requirements, see 21.3/p.2:

"[..] basic_string conforms to the the requirements of a Reversible=20
Container, as specified in (23.1)."

Hope that helps,

Daniel Kr=FCgler


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Tue, 25 May 2004 16:12:32 +0000 (UTC)
Raw View
kprateek88@yahoo.com (Prateek R Karandikar) wrote in message news:<607f883e.0405241021.60440bc3@posting.google.com>...
> template<typename Ch, typename Tr = std::char_traits<Ch>, typename A =
> std::allocator<Ch> >
> class std::basic_string
> {
>   //..
>  public:
>   typedef typename Tr::char_type value_type;
>   //...
> };
>
> In general, the type Ch may not be the same as the type typename
> Tr::char_type. Is there a requirement that these two be the same types? If
> yes, why this redundancy? If not, why this ambiguity?

Yes: 21.1.p3 says "To specialize those templates [referring to
templates defined in clauses 21.2 and 27]  ... Traits::char_type shall
be the same as CharT".

To remove the ambiguity, I presume you're thinking that the second
template parameter should be a template template parameter? Then you
could instantiate std::basic_string<mychar,mytraits>, with the same
effect as basic_string<mychar,mytraits<mychar> >. If that's what you
mean the reasons are partly historical. The string classes are much
older than the idea of template template parameters, and hence were
designed without them. At this point, the current template signatures
have to be maintained to allow for backward compatibility.

I also remember seeing an argument that type deduction works in a more
convenient fashion in certain situations, when the second parameter is
a class rather than a template. Sorry - I can't remember the details
of that argument.

The current design allows the traits class to not be a template, but
simply a single class that have a fixed typedef for char_type. I'm not
sure how important this aspect of the design is, but I'm sure that by
now someone, perhaps many people, has written code that depends upon
it. Hence, more backwards compatibility problems.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]