2

Consider the following program:

#include <iostream>

void myprint(const char* fmt, ...)
{
  std::cout << "1 ";
}

void myprint(const char* fmt, char *x)
{
  std::cout << "2 ";
}

int main()
{
  const char* s = "c";
  myprint("a", s);
  myprint("a", "b");
}

It produces different output:

My question is two-fold:

  1. Why does a string literal bind to a non-const char* even in the presence of -std=c++14? Isn't a string literal const since C++11?

  2. The ellipsis-overload is always ranked lowest. Why does clang select it? (one would think it doesn't allow binding to char* but if I remove the ellipsis overload, it still does - demo)

What's going on and who is right?

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • Well you see, one major problem is that your parameters fit in both signatures – Vivick Oct 24 '17 at 19:49
  • Modern GCC says: "warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]". Looks like GCC is just lenient, but knows that it's being naughty. (That is, GCC gives string literals the wrong type, presumably for reasons of "compatibility" with C.) – Kerrek SB Oct 24 '17 at 19:50
  • It is a bug in GCC and MSVC. Since C++11 the compiler is required to quietly select the first overload for `myprint("a", "b");`. GCC selects the second with a warning (or with an error in `-pedantic-errors` mode). Warning/error does not make its behavior correct. – AnT stands with Russia Oct 25 '17 at 18:06

1 Answers1

2

Why does a string literal bind to a non-const char* even in the presence of -std=c++14?

It's a deprecated conversion, which has been officially removed from the standard starting with C++11.

Isn't a string literal const since C++11?

No, a string literals is and has always been const.

The ellipsis-overload is always ranked lowest. Why does clang select it?

Because the other one is not valid. There is no conversion from const char* to char*, for the same reason that there is no way to convert a const std::string& to a std::string&.

So overload resolution skips that one and chooses the only remaining overload (which also happens to be valid), and prints 1.

one would think it doesn't allow binding to char* but if I remove the ellipsis overload, it still does

Yes, that is a non-standard extension, just like the gcc one. You should try to compile with -pedantic.

What's going on and who is right?

clang is definitely right. An extension is not allowed to modify the behavior of a well-formed C++ program ([intro.compliance]p8), so gcc and MSVC are wrong to use the second overload, as the standard doesn't support implicit conversions from const char* to char*, and should thus fall back on the first one.

To reiterate, your demo is in compliance with the standard because that program is ill-formed according to the standard (the string conversion) and they issue a diagnostic, and so it doesn't run afoul of the paragraph linked above.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162