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:
test(str1)
and test(str2)
choose the rvalue overload while they are lvalues?test(str1)
is ambiguous?Thank you.
- Which compiler is correct ?
GCC is correct.
- 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.
- 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.
- Is there a standard rule for this situation ?
See the ranking of implicit conversion sequences in overload resolution, and implicit conversions.
- How to fix the two last calls ?
It depends on your intent.
String literals are not rvalues. (→)
- How to fix the two last calls?
You can disambiguate everything with template specializations:
#include <iostream>
template<typename C, std::size_t N>
void test(const C (&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(const C (&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C, std::size_t N>
void test(const C (&&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(const C (&&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C, std::size_t N>
void test(C (&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(C (&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C, std::size_t N>
void test(C (&&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(C (&&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main(){
char str1[] = "";
char str2[] = "test";
test("");
test("test");
test(str1);
test(str2);
test(std::move(str1));
test(std::move(str2));
const char str3[] = "";
const char str4[] = "test";
test(std::move(str3));
test(std::move(str4));
}
gives
void test(const C (&)[1]) [with C = char]
void test(const C (&)[N]) [with C = char; long unsigned int N = 5]
void test(C (&)[1]) [with C = char]
void test(C (&)[N]) [with C = char; long unsigned int N = 5]
void test(C (&&)[1]) [with C = char]
void test(C (&&)[N]) [with C = char; long unsigned int N = 5]
void test(const C (&&)[1]) [with C = char]
void test(const C (&&)[N]) [with C = char; long unsigned int N = 5]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With