Home > Blockchain >  c check if a type is a fixed char array in a template
c check if a type is a fixed char array in a template

Time:03-24

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?

CodePudding user response:

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.

CodePudding user response:

It is not possible due to type decay; Result type of T (from function foo) is char*. You can figure it out via my example, just try to compile it:

#include <type_traits>

template<typename T>
struct is_inbuild_array final : std::false_type{};

template<typename T, std::size_t N>
struct is_inbuild_array<T[N]> final : std::true_type{};

template<typename T>
void f(T val)
{
    static_assert(
        is_inbuild_array<T>::value, 
        "Unsupported type"
    );
}

int main()
{
    char array [] = "Test";
    f(array);
}

But you can modify your function like this(use universal reference):

template<typename T>
void f(T&& val)
{
    static_assert(
        is_inbuild_array<std::remove_reference_t<T>>::value, 
        "Unsupported type"
    );
}

And it works well

  • Related