3

The following program displays 1. It seems completely unnatural to me. Do you know the reason behind this decision? How do you circumvent this problem, especially if you want to provide a constructor which can take both const char (&s)[n] and const char* s.

template <int n>
int f(const char (&s)[n]) {
  return 0;
}

int f(const char* s) {
  return 1;
}

int main() {
  std::cout << f("hello") << std::endl;

  return 0;
}

It's too bad, because you end up defining a constructor for string class with : const char*. Using that, the program must compute the length of the C-string at run-time which is a waste of time. On my own class, it takes 3ns to initialize a string with const char (&s)[n] and 20ns to initialize a string with const char*.

PS: This question is not the same as "What is array decaying?". First, we are in C++ here where the standard says:

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer to T.

which is by the way very fuzzy (can is not very precise). All I want to know is the rationale behind it.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
InsideLoop
  • 6,063
  • 2
  • 28
  • 55
  • Are you asking us to read the coders mind? And that's not "overloading strings" or something like that, there's no constructor here, and so on. You just don't understand the code. – deviantfan Aug 13 '17 at 09:50
  • I want to understand why such a decision has been made in the standard. Because, it makes the usage of `const char (&s)[n]` extremely difficult. And I don't see the advantage of it. – InsideLoop Aug 13 '17 at 09:52
  • 1
    @user0042 : I am not asking : what is array decaying ? I want to know why it is decayed when a better overload seems obvious. – InsideLoop Aug 13 '17 at 09:54
  • Anyways, your "[n]" in the template version is **not** the string length. It's (at best, if not decayed etc.) the array length, which can be longer,.That's your answer why a std::string constructor isn't using that to calculate the string length (I think you wanted to ask that) – deviantfan Aug 13 '17 at 09:54
  • 1
    Good question. I would have expected the output to be `0`. – juanchopanza Aug 13 '17 at 09:56
  • It's a template issue. Indeed, `int f(const char (&s)[6])` is ambiguous. – BiagioF Aug 13 '17 at 09:58
  • @deviantfan The point is that the template would allow getting the length of a string literal at compile time (but maybe the intrinsic `strlen` does that anyway.) – juanchopanza Aug 13 '17 at 09:58
  • 1
    Check out this answer: https://stackoverflow.com/a/43732803/8157187 – geza Aug 13 '17 at 09:59
  • @juanchopanza Yes, but luckily std::string can take non-literal values too. – deviantfan Aug 13 '17 at 09:59
  • @deviantfan So what? It could have had a template constructor deducing the length of the literal at compile time, if the output of the above code had been 0. – juanchopanza Aug 13 '17 at 10:00
  • (btw., changing the question 10 times doesn't help) – deviantfan Aug 13 '17 at 10:00
  • @deviantfan: I have changed it to acknowledge and reply to the criticism. I believe that presented that way, it is not a duplicate. – InsideLoop Aug 13 '17 at 10:09
  • I acknowledge the duplicate now with the new reference – InsideLoop Aug 13 '17 at 10:13
  • Indeed, even `std::is_same` says they are not the same type. The standard says _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._ § 2.14.5. – Benoît Aug 13 '17 at 10:21
  • @Benoit Here is particular catch that overload masks the template. if both functions were non-template or they both are templates, that would be ambiguous call , because array is allowed to decay. To disallow it would broke whole legacy syntax of array and cause way more problems than benefits. – Swift - Friday Pie Aug 13 '17 at 10:49
  • @InsideLoop: maybe you can achieve the same performance with constexpr functions (I've asked a similar [question](https://stackoverflow.com/questions/45541997/overloaded-function-of-parameters-reference-to-const-char-array-and-const-char-p) recently, and I was able to achieve the same functionality with constexpr functions) – geza Aug 13 '17 at 11:00
  • I got that from the linked answer. But i'm a little bit loss on why the type a string literal is an array reference when the standard says it's an array https://godbolt.org/g/XCPeuU – Benoît Aug 13 '17 at 11:06
  • @geza: I have tried that. Using constexpr works perfectly with clang (Apple LLVM 8.0.0) but does not work with g++ 7.1.0 nor icpc 2017.0.4. It's too bad. – InsideLoop Aug 13 '17 at 19:36
  • Should I open another question then ? – Benoît Aug 14 '17 at 16:32

0 Answers0