Consider the following code
#include <iostream>
#include <cstring>
template <int size>
void func(const char (&arr)[size])
{
//Prefer this function for const string literals.
std::cout << "Array of " << size - 1 << " bytes" << std::endl;
}
void func(const char *arr)
{
//Use this for all other strings that are not literals
std::cout << "String of " << strlen(arr) << " bytes" <<std::endl;
}
int main()
{
func("Hello!");
return 0;
}
How do I ensure that the template function is called in the example instead of the overload?
What I would like it that the templated function is called on string literals while the other is available for all other cases. With the templated function, i can avoid calling the strlen(). In my application both functions finally create a string_view object.
I would like to know how an overload is preferred.
CodePudding user response:
The problem is that array-to-pointer conversions count as exact match rank when ranking standard conversion sequences during overload resolution. Since the array overload is a template the pointer overload thus becomes a better match.
You could add a proxy object for the pointer overload, to force it into a worse conversion sequence than that of the array overload for when the argument is of type const char (&)[N]
:
namespace detail {
struct Proxy {
Proxy(const char *ptr) : ptr_{ptr} {};
operator const char *() const { return ptr_; }
private:
const char *ptr_;
};
} // namespace detail
template <int size> void func(const char (&arr)[size]) {
// Prefer this function for const string literals.
std::cout << "Array of " << size - 1 << " bytes" << std::endl;
}
void func(detail::Proxy const &proxy) {
// Use this for all other strings that are not literals
std::cout << "String of " << strlen(proxy) << " bytes" << std::endl;
}
int main() {
func("Hello!"); // Array of 6 bytes
const char *str = "Hello!";
func(str); // String of 6 bytes
}
CodePudding user response:
The trick with a reference makes inexact match to const char*
for a regular function.
#include <iostream>
#include <cstring>
template <size_t size>
void func(const char (&arr)[size])
{
//Prefer this function for const string literals.
std::cout << "Array of " << size - 1 << " bytes" << std::endl;
}
void func(const char *&arr)
{
//Use this for all other strings that are not literals
std::cout << "String of " << strlen(arr) << " bytes" <<std::endl;
}
int main()
{
func("Hello!");
const char *s = "s";
func(s);
return 0;
}
Output
Array of 6 bytes
String of 1 bytes