[SOLVED] c++ check if a type is a fixed char array in a template

Issue

I need to do some special handling of string types in a template I’m writing, but I’m running into a problem with fixed size char arrays. I’m aware I can write code like mentioned in this answer to create a wrapper: Const char array with template argument size vs. char pointer

But I was wondering if there was a way to test if this is a const char array from within a templated function with a static assert, something like this:

    template<typename T>
    void f(T& val /* a handful of other params */ )
    {
        static_assert(
            std::is_same_v < T, const char* > ||
            std::is_same_v < T, char[N] > || // how do I get/discard N here?
            std::is_same_v < T, std::string >
            , "Unsupported type" );
    }

My motivation for this is to avoid having a ton of function signatures for all valid type combinations, while still ensuring only valid types are allowed. Writing all those type declarations and definitions is a nightmare for a few reasons. But as strings can come in various fixed size arrays, I’m unsure how to check them without a wrapper to peel off the length data, but then I am back to writing a ton of wrappers which is exactly what I’m trying to avoid (if there is some way to write a simple reusable test using a single wrapper that would be ok, but I haven’t been able to figure one out). And for each string like this, if I was to manually add a wrapper for each time a string param appears in a param list, it will obviously double the number of declarations and definitions I need to write, creating a lot of redundant code. So is there any way to determine if a type is a fixed array type, and only then extract the pointer without the length so I can check it against a const char*? Or someway to ignore the array length and just check if it’s a char type array in my assert?

Solution

You cannot determine whether a T is an array like that directly, but the standard library provides traits for determining whether a given type is an array already: std::is_array.

Though std::is_array also accepts char[], which may be undesirable. In that case if you have access to C++20, you can use std::is_bounded_array. If you don’t have access to C++20, implementing one is rather trivial, or if you want to only check for char[N]:

template <class> struct is_bounded_char_array : std::false_type {};

template <size_t N> 
struct is_bounded_char_array<char[N]> : std::true_type {};

template <class> struct is_bounded_array : std::false_type {};

template <class T, size_t N> 
struct is_bounded_array<T[N]> : std::true_type {};

static_assert(!is_bounded_array<char>{});
static_assert(!is_bounded_array<char[]>{});
static_assert(is_bounded_array<char[42]>{});

Then, instead of std::is_same_v < T, char[N] >, you can say is_bounded_array<T>.

To get a const char* from any of your types, you could use std::string_view(t).data() instead of handling each case yourself.

Answered By – Fatih BAKIR

Answer Checked By – Pedro (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *