Search code examples
c++language-lawyeroverload-resolutionvalue-categories

Function overload for string literals lvalue and rvalue reference


The function test below is overloaded for lvalue empty strings, lvalue non-empty strings and rvalue strings. I tried to compile with Clang and GCC but in both case I do not have the result I expected.

#include <iostream>

void test(const char (&)[1]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }

template <unsigned long int N>
void test(const char (&)[N]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }

void test(char*&&){ std::cout << __PRETTY_FUNCTION__ << std::endl; }

int main(){
    char str1[] = "";
    char str2[] = "test";
    test("");
    test("test");
    test(str1);
    test(str2);
}

Output with clang version 6.0.0-1ubuntu2:

clang++ test.cpp -o test.out && ./test.out
void test(const char (&)[1])
void test(const char (&)[N]) [N = 5]
void test(char *&&)
void test(char *&&)

Output with g++ (MinGW.org GCC-8.2.0-3):

g++ test.cpp -o test.exe && test.exe
test.cpp: In function 'int main()':
test.cpp:15:11: error: call of overloaded 'test(char [1])' is ambiguous
  test(str1);
           ^
test.cpp:3:6: note: candidate: 'void test(const char (&)[1])'
 void test(const char (&)[1]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
      ^~~~
test.cpp:6:6: note: candidate: 'void test(const char (&)[N]) [with long unsigned int N = 1]'
 void test(const char (&)[N]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
      ^~~~
test.cpp:8:6: note: candidate: 'void test(char*&&)'
 void test(char*&&){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
      ^~~~

My questions are:

  1. Which compiler is correct?
  2. With Clang, why test(str1) and test(str2) choose the rvalue overload while they are lvalues?
  3. With GCC, why the call test(str1) is ambiguous?
  4. Is there a standard rule for this situation?
  5. How to fix the two last calls?

Thank you.


Solution

    1. Which compiler is correct ?

    GCC is correct.

    1. With clang, why str1 and str2 choose the rvalue overload while they are lvalues ?

    Clang is wrong on test(str1);, it should be ambiguous. For test(str2);, str2 could convert to pointer implicitly, i.e. the array-to-pointer decay. The converted char* is an rvalue. For the same reason as #3, the implicit conversion sequences have the same ranking, then non-template function is prefered; test(char*&&) is selected.

    1. With gcc, why call with str1 is ambiguous ?

    For test(const char (&)[1]) to be called, qualification conversion from char[1] to const char[1] is required; for test(char*&&) to be called, array-to-pointer conversion is required. Both are qualified as exact match and have the same ranking.

    1. Is there a standard rule for this situation ?

    See the ranking of implicit conversion sequences in overload resolution, and implicit conversions.

    1. How to fix the two last calls ?

    It depends on your intent.