Home > Mobile >  template function taking array argument vs overload function taking pointer argument
template function taking array argument vs overload function taking pointer argument

Time:05-06

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
  •  Tags:  
  • c
  • Related