Disclaimer: This is an XY problem kind question.
Is it possible to resolve template <typename T>
to (const T (&)[N])
overload instead of (const T*)
?
For example:
template <typename T>
void _print_type(T)
{
std::cout << "not a c array\n";
}
template <typename T, size_t N>
void _print_type(const T (&)[N])
{
std::cout << "ref c array\n";
}
template <typename T>
void _print_type(const T *)
{
std::cout << "pointer to c array\n";
}
template <typename T>
void print_type(T t)
{
_print_type(t);
}
int main(){
print_type("oceanic"); // prints "pointer to c array\n"
}
And why _print_type("oceanic");
results in ambiguous call? Isn't it logical to prefer an overload with reference to array when there is one?
The XY problem (not part of the question):
Concatenation function which takes differen string types
const ct_string staticString = "I am static";
concat("string literal", staticString, "another literal"); // yields contigeous ct_string
concat("string literal", staticString, std::string("dynamic string")); // yields std::string
- One can figure the lenght of a
const char*
at compile time. One can not enforce a check whetherconst char *
is a string literal. - One can not use a variadic list of
ct_string
for arguments liketemplate <size_t ... N> constexpr auto concat(ct_string<N>...)
sinceN
is impossible to deduce even with deduction guides forct_string
.
CodePudding user response:
CWG recently decided that binding a reference-to-array to an array argument should be considered a better implicit conversion than decaying the array to a pointer. CWG 1789
Until the wording of the standard is updated and compilers start implementing the new behaviour, you have to work around the ambiguity by taking the argument by forwarding reference:
template <typename T>
void print_type(T&& t) {
if constexpr(std::is_pointer_v<std::remove_reference_t<T>>) {
// call pointer implementation
} else if constexpr(std::is_array_v<std::remove_reference_t<T>>) {
// call array implementation
} else {
// ...
}
}