0

The problem is I don't understand why those should be separate. Why not use one class, like CharType, that would contain both the logic of char traits and char type. I mean replace that:

template <class _Elem, class _Traits = char_traits<_Elem>, class _Alloc = allocator<_Elem>>
class basic_string { /*...*/ };

with that:

template <class ExtendedTraits, class _Alloc = allocator<_Elem>>
class basic_string { /*...*/ };

where ExtendedTraits is the presaid combination of _Elem and _Traits, that might look like that:

template<_CharType> //all the necessary template parameters
class extended_traits 
{
public:
    using value_type = _CharType;
private:
    _CharType _elem;
public:
//... all methods, that used to be in char_traits but now non-static and accepting one parameter

};

I tried to implement both approaches, both of them do work, but there may be some problems I still do not notice.

Capy Maths
  • 79
  • 6
  • 5
    What do you prefer to see, `basic_string` or `basic_string>`? – n. m. could be an AI Nov 13 '22 at 12:57
  • 4
    If one were to trace the history and the lineage of `basic_string`, it's almost a certainty that we'll find that the char type came first, and the traits type was added as an additional, defaulted template parameter in order to preserve backwards compatibility with existing code. – Sam Varshavchik Nov 13 '22 at 12:59
  • The `char` traits *could* have been presumed & referred to, rather than have them be a parameter with a default value. But then they couldn't be varied for (say) needed `char` that had different traits. And likely the original `string` did just that (see Sam's comment). – Eljay Nov 13 '22 at 13:02
  • 1
    actually there do have `Traits::char_type` that match `_Elem` (and the allocator's `value_type`) – apple apple Nov 13 '22 at 14:42
  • I think it just make sense, I want a container of `char`, the trait and allocator is just additional to it. – apple apple Nov 13 '22 at 14:44
  • But we never even happen to use basic_string, we usually take advantage of merely std::string. It's quite transparent to an external user whether std::string is defined as basic_string,...> or basic_string,...>. – Capy Maths Nov 13 '22 at 15:07
  • @CapyMaths btw, your replacement simply doesn't work, because of lack of `_Elem` definition. – apple apple Nov 13 '22 at 15:10
  • How about extended_ch_traits::value_type? – Capy Maths Nov 13 '22 at 15:11
  • @CapyMaths `char_trait` doesn't have `value_type` either, nor is yours. – apple apple Nov 13 '22 at 15:11
  • @CapyMaths anyway the point is you don't need to specify what default is good enough. why specify the whole trait while [the default one](https://en.cppreference.com/w/cpp/string/char_traits) works? – apple apple Nov 13 '22 at 15:14
  • @appleapple still can't grasp why we can't we achieve this using my "approach". We could create some base `class char_traits` with default definitions and then override all we need via inheritance just as stl developers do. Suppose `extended_traits` would also contain `value_type`. Now we can create our own string accustomed to my "concept of traits" : `using string = my_string,...>;` What's the problem here? – Capy Maths Nov 13 '22 at 15:33
  • "But we never even happen to use" Until we see our first compiler error, or start using a debugger. – n. m. could be an AI Nov 13 '22 at 15:34
  • @CapyMaths of course you can do it in many ways and it would compile, not saying it'd make sense (at least for me). – apple apple Nov 13 '22 at 15:35

1 Answers1

0

I think it makes more sense to separate the character type from the Traits object. Traits is an additional class for character comparisons and such, which is inherently different from the character type. Your method would work, but the equivalent would be like combining two completely different functions into the same function.

It's also more immediately obvious what character type the string is using. For example:

typedef string basic_string<char>;

is much more obvious than

typedef string basic_char<extended_traits<char>, ...>;

as there is an additional level of nesting and more characters and such.

At the end of the day, we don't care about what Traits is, we care about what character type the string is. Traits is for internal operations, and is meant to be abstracted away; as such, it's kept away from the character type, which is meant to be more obvious as it indicates what types of values the string can contain.

At least, that's my view on things.

Besides, it's not necessarily a bad thing to have more template arguments for std::basic_string, especially since there's only ever one template argument you really need to define a parameter for - the other template are given default types. It's not often that I would need to define my own Traits class. But if I wanted to define my own separate string class with a custom character or something like that, I would have to define a Traits class for it, even if I have written my assignment operator and comparison operators and everything else. That would be especially irritating.