Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function overloading for const char*, const char(&)[N] and std::string

What I want to achieve is to have overloads of a function that work for string literals and std::string, but produce a compile time error for const char* parameters. The following code does almost what I want:

#include <iostream>
#include <string>

void foo(const char *& str) = delete;

void foo(const std::string& str) {
    std::cout << "In overload for const std::string&     : " << str << std::endl;
}

template<size_t N>
void foo(const char (& str)[N]) {
    std::cout << "In overload for array with " << N << " elements : " << str << std::endl;
}   

int main() {
    const char* ptr = "ptr to const";
    const char* const c_ptr = "const ptr to const";
    const char arr[] = "const array";
    std::string cppStr = "cpp string";

    foo("String literal");
    //foo(ptr); //<- compile time error
    foo(c_ptr); //<- this should produce an error
    foo(arr);   //<- this ideally should also produce an error
    foo(cppStr);
}

I'm not happy, that it compiles for the char array variable, but I think there is no way around it if I want to accept string literals (if there is, please tell me)

What I would like to avoid however, is that the std::string overload accepts const char * const variables. Unfortunately, I can't just declare a deleted overload that takes a const char * const& parameter, because that would also match the string literal.

Any idea, how I can make foo(c_ptr) produce a compile-time error without affecting the other overloads?

like image 733
MikeMB Avatar asked Feb 08 '23 03:02

MikeMB


2 Answers

This code does what is needed (except the array - literals are arrays, so you can't separate them)

#include <cstddef>
#include <string>

template <class T>
void foo(const T* const & str) = delete;

void foo(const std::string& str);

template<std::size_t N>
void foo(const char (& str)[N]);

int main() {
    const char* ptr = "ptr to const";
    const char* const c_ptr = "const ptr to const";
    const char arr[] = "const array";
    std::string cppStr = "cpp string";

    foo("String literal");
    //foo(ptr); //<- compile time error
    // foo(c_ptr); //<- this should produce an error
    foo(arr);   //<- this ideally should also produce an error
    foo(cppStr);
}
like image 195
SergeyA Avatar answered Feb 10 '23 16:02

SergeyA


In order for your deleted function to not be a better match than the template function, so that string literals still work, the deleted function needs to also be a template. This seems to satisfy your requirements (though the array is still allowed):

template <typename T>
typename std::enable_if<std::is_same<std::decay_t<T>, const char*>::value>::type
foo(T&& str) = delete;

Demo.

like image 37
aschepler Avatar answered Feb 10 '23 15:02

aschepler