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.
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.