4

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?

MikeMB
  • 20,029
  • 9
  • 57
  • 102
  • There is *no difference* between the type of a char array and a string literal, so you cannot throw out one without the other. But I think your other requirement is satisfiable. – Tavian Barnes Jan 05 '16 at 21:51
  • @Tavian Barns: I was wondering, if one could use the fact, that a string literal is also a constant expression (of course you can also create a constexpr array) – MikeMB Jan 05 '16 at 22:19

3 Answers3

4

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);
}
MikeMB
  • 20,029
  • 9
  • 57
  • 102
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Thank you. With that template function, I believe the first overload (for `const char *& str`) is no longer necessary - right? – MikeMB Jan 05 '16 at 22:07
3

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.

aschepler
  • 70,891
  • 9
  • 107
  • 161
1

In modern versions of the language you may create some custom type and user-defined literal that will create it, so that it will be possible to pass "this"_SOMEWORDS, but not just c string literal, chat pointer or char array.

It doesn't exactly satisfy your requirements to pass string literal but I think it's good enough, especially because it forbids also arrays

RiaD
  • 46,822
  • 11
  • 79
  • 123
  • That's actually a very interesting idea, as it allows one to distinguish between a char array and a string literal. But it doesn't prevent the `std::string` overload from accepting the `const char * const` parameter. – MikeMB Jan 05 '16 at 22:51
  • @MikeMB Just deleting it (const char* overload) will work now – RiaD Jan 05 '16 at 22:53
  • right - sorry, its getting late. Is it possible to get the length of the string literal at compiletime (as in my example function with the template parameter) this way? – MikeMB Jan 05 '16 at 23:15
  • @MikeMB, unfortunately I didn't manage to do that at the moment. It seems that template form of only available for integer/floaing literals – RiaD Jan 06 '16 at 14:08
  • No problem, it isn't a hard requirement.Thanks again. So far I've only used user defined literals in a few toy examples and just didn't think in that direction for the problem at hand. – MikeMB Jan 06 '16 at 14:18