c++ - Sobrecarga de funciones para los literales de cadena lvalue y rvalue reference
language-lawyer overload-resolution (3)
- ¿Qué compilador es correcto?
El CCG es correcto.
- 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.
- 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.
- ¿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 .
- ¿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:
- ¿Qué compilador es correcto?
-
Con Clang, ¿
test(str1)
quétest(str1)
ytest(str2)
eligen la sobrecarga del valor mientras son valores? -
Con GCC, ¿por qué la
test(str1)
llamadatest(str1)
es ambigua? - ¿Existe una regla estándar para esta situación?
- ¿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. ( → )
- ¿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]