type_trait is_char

847 views
Skip to first unread message

TheIdeasMan

unread,
Aug 3, 2015, 2:41:31 AM8/3/15
to ISO C++ Standard - Discussion
Hello all,

At the moment the type_trait   is_char is not part of the C++ standard, however boost does have it at:

#include <boost/spirit/home/support/string_traits.hpp>

The existing standard does have traits for basic types and generic traits such as is_arithmetic , so
I was wondering if there was a reason for this not to be part of the current standard, or is it a trivial ommision?



dancing...@gmail.com

unread,
Aug 3, 2015, 4:26:21 AM8/3/15
to ISO C++ Standard - Discussion, dancing...@gmail.com



The other question should be: would this is_char type trait proposal be a reasonable candidate to be included in the next standard ?

charleyb123 .

unread,
Aug 3, 2015, 8:17:15 AM8/3/15
to std-dis...@isocpp.org, dancing...@gmail.com
<snip>,
 
The other question should be: would this is_char type trait proposal be a reasonable candidate to be included in the next standard ?

IMHO this quickly gets ambiguous because "wide-char" and "short-int" are the same thing, and it is only (human) programmer-context that can disambiguate between whether a "short" is intended to be a "character" or "integral" instance.

--charley

Andrey Semashev

unread,
Aug 3, 2015, 8:27:00 AM8/3/15
to std-dis...@isocpp.org
On 03.08.2015 15:17, charleyb123 . wrote:
> On Mon, Aug 3, 2015 at 12:41 AM, TheIdeasMan <dancing...@gmail.com
> <mailto:dancing...@gmail.com>> wrote:
>
> Hello all,
>
> At the moment the type_trait *is_char* is not part of the C++
> standard, however boost does have it at:
>
> |#include<boost/spirit/home/support/string_traits.hpp>|
>
> The existing standard does have traits for basic types and generic traits such as is_arithmetic , so
> I was wondering if there was a reason for this not to be part of the
> current standard, or is it a trivial ommision?
>
> <snip>,
>
> The other question should be: would this *is_char *type trait
> proposal be a reasonable candidate to be included in the next standard ?
>
>
> IMHO this quickly gets ambiguous because "wide-char" and "short-int" are
> the same thing,

No they are not. They are only in a broken MSVC mode which should never
be used.

For one I would find such a trait useful. In addition to char and
wchar_t the trait would also return true for char16_t and char32_t.

TheIdeasMan

unread,
Aug 3, 2015, 8:50:22 AM8/3/15
to ISO C++ Standard - Discussion


On Monday, 3 August 2015 21:57:00 UTC+9:30, Andrey Semashev wrote:

No they are not. They are only in a broken MSVC mode which should never
be used.

For one I would find such a trait useful. In addition to char and
wchar_t the trait would also return true for char16_t and char32_t.

Yes, it was meant to be a generic trait - just like is_arithmetic , so it should work for all the unsigned versions and all the different widths of char.

I was looking at the boost implementation, it didn't seem similar to what I do: I use a bunch of is_same traits to achieve what I wanted. But seems to be more than what would be necessary if it was part of the standard.

template< typename C > struct is_char : std::integral_constant<bool, std::is_same<C, char>::value || std::is_same<C, char16_t>::value || std::is_same<C, char32_t>::value || std::is_same<C, wchar_t>::value> {};

Cheers

David Krauss

unread,
Aug 3, 2015, 10:53:57 AM8/3/15
to std-dis...@isocpp.org
Within the strings library, at least, character manipulation is done through specializations of std::char_traits. User-defined types can be “char-like,” but the builtin signed char and unsigned char have no char_traits specialization, so the operations don’t work.

A standardization proposal should justify what criteria and common features unite “character types,” because signed char and char32_t have few use cases in common.

As for the linked Boost header, it only blesses char and wchar_t, with no C++11 support. It might be good to find a better example.

Andrey Semashev

unread,
Aug 3, 2015, 11:23:26 AM8/3/15
to std-dis...@isocpp.org
On 03.08.2015 17:53, David Krauss wrote:
>
>> On 2015–08–03, at 2:41 PM, TheIdeasMan <dancing...@gmail.com
>> <mailto:dancing...@gmail.com>> wrote:
>>
>> Hello all,
>>
>> At the moment the type_trait *is_char* is not part of the C++
>> standard, however boost does have it at:
>>
>> |#include <boost/spirit/home/support/string_traits.hpp>|
>>
>> The existing standard does have traits for basic types and generic
>> traits such as is_arithmetic , so
>> I was wondering if there was a reason for this not to be part of the
>> current standard, or is it a trivial ommision?
>
> Within the strings library, at least, character manipulation is done
> through specializations of std::char_traits. User-defined types can be
> “char-like,” but the builtin signed char and unsigned char have no
> char_traits specialization, so the operations don’t work.
>
> A standardization proposal should justify what criteria and common
> features unite “character types,” because signed char and char32_t have
> few use cases in common.
>
> As for the linked Boost header, it only blesses char and wchar_t, with
> no C++11 support. It might be good to find a better example.

I have a similar trait in Boost.Log:

https://github.com/boostorg/log/blob/master/include/boost/log/detail/is_character_type.hpp

The trait is useful when you want to write generic code that is supposed
to be used in the context of strings, like:

template< typename T >
typename enable_if< is_char< T >::value, basic_string< T > >
foo(const T* str);

Arrays of such types can be interpreted as C-style strings. As such you
should be able to use std::basic_string, string IO and character
manipulation (<ctype>, <codecvt>, etc.) with these types.

It's true that std::char_traits is only specialized for character types,
but you can't use this fact without getting hard compile errors. I
believe, std::char_traits should be described in terms of is_char
instead, i.e. be specialized for all types for which is_char returns true.

TheIdeasMan

unread,
Aug 4, 2015, 3:17:02 AM8/4/15
to ISO C++ Standard - Discussion

Hello again,

Thank you very much for all that have replied :+)

If I could fist ask an admin question: How to get rid of my email address on replies I have made? I looked all through my profile & couldn't see any where to change it. I did join the group - maybe it is only there for the first one?

Next, I should point out that I have limited knowledge of c++, I subjectively (hopefully realistically) place myself somewhere at the lower end of intermediate level. However this doesn't stop me from thinking about things and asking questions :+) I apologise in advance if this turns out to only benefit my education rather than lead to a trivial change in the standard.

Now my motivation for starting this topic was a purely logical one: as mentioned earlier we already have some generic traits like is_arithmetic , so why not is_char ? Since then I have found out about std::char_traits (Thanks David Krauss), but now I am not sure if that is the same (or better than ) as what I have stumbled upon.

And this motivation came from wanting to avoid tedious template specialisations. For example, say I want a Circle template, and for the type of the Radius char does not make sense. So to avoid writing the exact same template specialisation for each of short , int , long , float , double, long double, I used the trait_types along with some static_asserts  , and I will get to that aspect of it shortly.

So here is some (may be) pedagogical code:

#ifndef CCIRCLE_H
#define CCIRCLE_H

#include <iostream>
#include <type_traits>


template< typename C >
struct is_char : std::integral_constant<bool,
                     std::is_same<C, char>::value      ||
                     std::is_same<C,  char16_t>::value ||
                     std::is_same<C, char32_t>::value  ||
                     std::is_same<C,  wchar_t>::value>
                     {};

template<typename T >
class CCircle {
public:
  static_assert(std::is_arithmetic<T>::value
                && !is_char<T>::value, "Type must be arithmetic, but not char");

   CCircle(T radius) : m_Radius(radius) {}

   void Print() const {
      std::cout << m_Radius << "\n";
   }

private:
   T m_Radius;
};


Now, I have used static_assert - so this is obviously a compile time thing.

But with the way I have declared my is_char :

  • It's derived from std::integral_constant , which is the base class for all the type traits - I am not attempting to extend an existing trait
  • It uses is_same 
So I am wondering whether this will work at runtime - all these traits are TMP stuff , so I am hoping that it will. And if it does, one could use in conjunction with exceptions or other means of error handling. I should really test that myself though.

Right, so finally I am wondering whether this is different to what is in std::char_traits - are all the types and widths covered there?  Andrey has mentioned they only work at compile time.

Or do I have something fundamentally wrong?

Regards to all


Jim Porter

unread,
Aug 4, 2015, 11:56:56 AM8/4/15
to std-dis...@isocpp.org
On 8/3/2015 9:53 AM, David Krauss wrote:
>> On 2015–08–03, at 2:41 PM, TheIdeasMan <dancing...@gmail.com> wrote:
>> At the moment the type_trait *is_char* is not part of the C++
>> standard, however boost does have it at:
>>
>> |#include <boost/spirit/home/support/string_traits.hpp>|
>>
>> The existing standard does have traits for basic types and generic
>> traits such as is_arithmetic , so
>> I was wondering if there was a reason for this not to be part of the
>> current standard, or is it a trivial ommision?
[snip]
> A standardization proposal should justify what criteria and common
> features unite “character types,” because signed char and char32_t have
> few use cases in common.

This trait is particularly useful for dealing with string literals,
which, despite being arrays/pointers, may be treated significantly
differently from other array/pointer types in your code. In my case, I
use a trait like this to print a debug representation of a string. The
trait lets me print char-like arrays like `"foo"`, but arrays of other
types like `[1, 2, 3]`.

> As for the linked Boost header, it only blesses char and wchar_t, with
> no C++11 support. It might be good to find a better example.

I created a trait[1] exactly like this for a project (it's C++14-only,
so the code is pretty simple), but called it is_any_char, since is_char
sounds too much like std::is_same<T, char> to me.

[1]
https://github.com/jimporter/mettle/blob/7584abd870be5362a838b982226c0d65e3d7111f/include/mettle/output/traits.hpp#L35-L44

- Jim

TheIdeasMan

unread,
Aug 5, 2015, 6:48:36 AM8/5/15
to ISO C++ Standard - Discussion


Thanks Jim,

You have a good point about the name, mine wasn't as good.

So to summarise so far: We have some who think they would benefit from having such a trait, some who have already invented their own, the boost library which has 2 different ones (that may not cover all situations), and I know of another highly regarded person who advised me to try and get it into boost first then aim for c++.

With regard to my earlier comments about use of this trait at runtime - I am not sure that I thought that through sufficiently.

Anyway thanks for everyone's advice so far :+) if anyone has more comments, they are most welcome.

Regards


Edward Smith-Rowland

unread,
Aug 12, 2015, 4:21:30 PM8/12/15
to ISO C++ Standard - Discussion


I keeping with other traits such as is_integral and is_floating_point I think is_character is better.  The generic name indicates that it should apply to char, wchar_t, char16_t, char32_t, ...
I thought is_char looks like it applies only to char.

Also, we have bool_constant and is_same_v to make things neater.

template<typename C>
  struct is_char
  : std::bool_constant<std::is_same_v<C, char> ||
                       std::is_same_v<C, char16_t> ||
                       std::is_same_v<C, char32_t> ||
                       std::is_same_v<C, wchar_t>>
  {};

Reply all
Reply to author
Forward
0 new messages