c++ language-lawyer overload-resolution value-categories

c++ - Sobrecarga de funciones para los literales de cadena lvalue y rvalue reference



language-lawyer overload-resolution (3)

  1. ¿Qué compilador es correcto?

El CCG es correcto.

  1. Con el sonido metálico, ¿por qué str1 y str2 eligen la sobrecarga del valor mientras son valores?

Clang está mal en la test(str1); , debería ser ambiguo. Para test(str2); , str2 podría convertirse a puntero implícitamente, es decir, la descomposición de matriz a puntero. El char* convertido es un valor r. Por la misma razón que el n. ° 3, las secuencias de conversión implícitas tienen la misma clasificación, luego se prefiere la función sin plantilla; test(char*&&) está seleccionado.

  1. Con gcc, ¿por qué la llamada con str1 es ambigua?

Para que se test(const char (&)[1]) , se requiere la conversión de calificación de char[1] a const char[1] ; para llamar a test(char*&&) , se requiere la conversión de matriz a puntero. Ambos están calificados como coincidencia exacta y tienen el mismo ranking.

  1. ¿Existe una regla estándar para esta situación?

Vea el ranking de secuencias de conversión implícitas en resolución de sobrecarga y conversiones implícitas .

  1. ¿Cómo arreglar las dos últimas llamadas?

Depende de tu intención.

La siguiente test función está sobrecargada para las cadenas vacías lvalue, las cadenas no vacías lvalue y las cadenas rvalue. Traté de compilar con Clang y GCC pero en ambos casos no tengo el resultado que esperaba.

#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); }

Salida con clang versión 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 *&&)

Salida con 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; } ^~~~

Mis preguntas son:

  1. ¿Qué compilador es correcto?
  2. Con Clang, ¿ test(str1) qué test(str1) y test(str2) eligen la sobrecarga del valor mientras son valores?
  3. Con GCC, ¿por qué la test(str1) llamada test(str1) es ambigua?
  4. ¿Existe una regla estándar para esta situación?
  5. ¿Cómo arreglar las dos últimas llamadas?

Gracias.


Gracias @songyuanyao por su respuesta, ahora entiendo por qué se elige test(char*&&) en los dos últimos casos. Pude eliminar la ambigüedad con la especialización de plantilla en la primera sobrecarga gracias a la respuesta de @Darklighter también.

Entonces resolví mi problema como a continuación:

#include <iostream> template <unsigned long int N> void test(const char (&)[N]){ std::cout << __PRETTY_FUNCTION__ << " //non-empty literal" << std::endl; } template <> void test(const char (&)[1]){ std::cout << __PRETTY_FUNCTION__ << " //empty literal" << std::endl; } void test(char*&&){ std::cout << __PRETTY_FUNCTION__ << " //string variable" << std::endl; } int main(){ char str1[] = ""; char str2[] = "test"; test(""); test("test"); test(str1); test(str2); }

Salida:

clang++ test.cpp -o test.out && ./test.out void test(const char (&)[1]) //empty literal void test(const char (&)[N]) [N = 5] //non-empty literal void test(char *&&) //string variable void test(char *&&) //string variable g++ test.cpp -o test.exe && test.exe void test(const char (&)[N]) [with long unsigned int N = 1] //empty literal void test(const char (&)[N]) [with long unsigned int N = 5] //non-empty literal void test(char*&&) //string variable void test(char*&&) //string variable


Los literales de cadena no son valores. ( )

  1. ¿Cómo arreglar las dos últimas llamadas?

Puede desambiguar todo con especializaciones de plantilla:

#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)); }

da

prueba nula (const C (&) [1]) [con C = char]
prueba nula (const C (&) [N]) [con C = char; largo sin signo int N = 5]
prueba nula (C (&) [1]) [con C = char]
prueba nula (C (&) [N]) [con C = char; largo sin signo int N = 5]
prueba nula (C (&&) [1]) [con C = char]
prueba nula (C (&&) [N]) [con C = char; largo sin signo int N = 5]
prueba nula (const C (&&) [1]) [con C = char]
prueba nula (const C (&&) [N]) [con C = char; largo sin signo int N = 5]