11

From: Is it safe to overload char* and std::string?

#include <string>
#include <iostream>
void foo(std::string str) {
  std::cout << "std::string\n";
}

void foo(char* str) {
  std::cout << "char*\n";
}

int main(int argc, char *argv[]) {
  foo("Hello");
}

The above code prints "char*" when compiled with g++-4.9.0 -ansi -pedantic -std=c++11.

I feel that this is incorrect, because the type of a string literal is "array of n const char", and it shouldn't be possible to initialize a non-const char* with it, so the std::string overload should be selected instead. Is gcc violating the standard here?

Community
  • 1
  • 1
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 7
    You also get a warning: *deprecated conversion from string constant to 'char*' (You need `-Wall` or `-Wwrite-strings` for it). And no, it's not correct. – jrok Jul 09 '14 at 19:40
  • From my experiences, GCC and Clang don't actually outlaw it like they should, probably because of the sheer amount of code that would break. – chris Jul 09 '14 at 19:40
  • If you want to improve the other question, then edit it! – πάντα ῥεῖ Jul 09 '14 at 19:40
  • 4
    @jrok What use is a warning if the compiler actually compiles a well-formed program incorrectly? :/ – Brian Bi Jul 09 '14 at 19:43
  • It's a diagnostic, and that's enough as far the standard is concerned. – jrok Jul 09 '14 at 19:44
  • 2
    @jrok: Not in this case, because we have a program with perfectly well-defined behavior and the compiler compiled it wrong. That moves it from "conforming language-extension" over the divide into non-conforming implementation. – Deduplicator Jul 09 '14 at 19:45
  • 3
    [Clang bug 16314](http://llvm.org/bugs/show_bug.cgi?id=16314). – T.C. Jul 09 '14 at 19:51
  • 2
    @Deduplicator That's not really the right bug. That one's actually complaining that the compiler has the temerity of issuing a warning when using a string literal with a function taking `char *`. – T.C. Jul 09 '14 at 20:44
  • @T.C.: Ok, will look again. Thanks for proof-reading. – Deduplicator Jul 09 '14 at 20:50

1 Answers1

7

First, the type of string literals: They are all constant arrays of their character type.

2.14.5 String literals [lex.string]

7 A string literal that begins with u8, such as u8"asdf", is a UTF-8 string literal and is initialized with the given characters as encoded in UTF-8.
8 Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration (3.7).
9 A string literal that begins with u, such as u"asdf", is a char16_t string literal. A char16_t string literal has type “array of n const char16_t”, where n is the size of the string as defined below; it has static storage duration and is initialized with the given characters. A single c-char may produce more than one char16_t character in the form of surrogate pairs.
10 A string literal that begins with U, such as U"asdf", is a char32_t string literal. A char32_t string literal has type “array of n const char32_t”, where n is the size of the string as defined below; it has static storage duration and is initialized with the given characters.
11 A string literal that begins with L, such as L"asdf", is a wide string literal. A wide string literal has type “array of n const wchar_t”, where n is the size of the string as defined below; it has static storage duration and is initialized with the given characters.

Next, lets see that we only have standard array decay, so from T[#] to T*:

4.2 Array-to-pointer conversion [conv.array]

1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.

And last, lets see that any conforming extension must not change the meaning of a correct program:

1.4 Implementation compliance [intro.compliance]

1 The set of diagnosable rules consists of all syntactic and semantic rules in this International Standard except for those rules containing an explicit notation that “no diagnostic is required” or which are described as resulting in “undefined behavior.”
2 Although this International Standard states only requirements on C++ implementations, those requirements are often easier to understand if they are phrased as requirements on programs, parts of programs, or execution of programs. Such requirements have the following meaning:

  • If a program contains no violations of the rules in this International Standard, a conforming implementation shall, within its resource limits, accept and correctly execute2 that program.
  • If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this Standard as “conditionally-supported” when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.
  • If a program contains a violation of a rule for which no diagnostic is required, this International Standard places no requirement on implementations with respect to that program.

So, in summary, it's a compiler bug.

(Before C++11 (C++03) the conversion was allowed but deprecated, so it would have been correct. A diagnostic in case it happened would not have been required but provided as a quality of implementation issue.)

It's a GCC bug (bug-report not found yet), and also a clang bug (found by T.C.).

The test-case from the clang bug-report, which is much shorter:

void f(char*);
int &f(...);
int &r = f("foo");
Deduplicator
  • 44,692
  • 7
  • 66
  • 118