Search code examples
c++templatesc++20if-constexpr

How to match all string types with std::is_same_v


I'm trying to use templates to generify a method. However I'm struggling to match string types like string char * literals. See the following code example:

template<typename ValueType>
void match_data_type(ValueType value) {
    if constexpr (std::is_same_v<std::remove_cvref_t<ValueType>, bool>) {
        std::cout << "bool" << std::endl;
    } else if constexpr (std::is_same_v<std::remove_cvref_t<ValueType>, char>) { // Useless?
        std::cout << "char" << std::endl;
    } else if constexpr (std::is_same_v<std::remove_cvref_t<ValueType>, char *>) {
        std::cout << "char *" << std::endl;
    } else if constexpr (std::is_same_v<std::remove_cvref_t<ValueType>, char[]>) { // Useless?
        std::cout << "char[]" << std::endl;
    } else if constexpr (std::is_same_v<std::remove_cvref_t<ValueType>, std::string>) {
        std::cout << "std::string" << std::endl;
    } else {
        std::cout << "Not matched!" << std::endl;
    }
}

Test cases:

match_data_type(false);
char *string_buffer = "Text";
match_data_type(string_buffer);
match_data_type("Test");
std::string standard_string = "Test";
match_data_type(standard_string);

Output:

bool
char *
Not matched!
std::string

The surprising part to me is the Not matched! output since I passed a string literal directly into the method and it didn't match any of the cases.

1)Is there any constexpr check which matches all types of char *? Then I need another case for std::string objects so I can pass the .c_str() into the respective legacy method which expects char * as its argument.

2) Is there a way to statically fail the compilation if none of the cases are matched? (e.g. the else branch is taken). static_assert(false) in the else branch does not work since it will always take effect, regardless of the passed parameter type.


Solution

  • String literals are constant.

    The type of "hello" is char const[6], which would decay (since you're taking by value) to char const*. You have to check against that, not char*.


    For the rest of the code, the char check isn't useless (you could certainly call match_data_type('c')) but the char[] one is -- the parameter will never have array type, since it's a value.

    More broadly, std::remove_cvref_t<ValueType> will always be just ValueType unless you're explicitly providing that parameter -- since that type will never be deduced to be a reference type or have qualifiers.