7

considerar los siguientes constructores para T:Problemas con el fin resolución constructor

struct T { 
    T(const bool) { std::cout << "T(const bool)" << endl; } 
    T(const std::string&) { std::cout << "T(const std::string&)" << endl; } 
}; 

T t(""); 
  1. ¿Por qué T(const bool) tienen prioridad sobre T(const std::string&) en la construcción de t?
  2. Dado que la precedencia anterior podría causar confusión a los usuarios que esperan que se llame T(const std::string&), ¿qué puedo hacer para llamar T(const std::string&) implícitamente al pasar literales de cadena al constructor de T. Por ahora, el único trabajo que he encontrado es agregar otro constructor, que tiene la prioridad más alta:

    T(const char* s) 
    { 
        std::cout << "T(const char*)" << endl; 
        *this = std::string(s); 
    } 
    
  3. Aparte de la solución anterior, declarando explicit T(const bool) para evitar la confusión no se soluciona el problema anterior: en este caso, aunque T t = "" está prohibida, por eso es la forma T t("") todavía está permitido y llama al T(const bool)?

Respuesta

8

¿Por qué T(const bool) tienen prioridad sobre T(const std::string&) cuando se construye t?

"" es del tipo char[1]; esto es implícitamente convertible a char const* a través de la conversión de matriz a punta. Un puntero es implícitamente convertible a bool, con todos los punteros no nulos que se convierten en true y todos los punteros nulos se convierten en false. Estas son conversiones estándar "integradas".

La conversión char const* -> std::string es una conversión declarada por el usuario: utiliza un constructor de conversión de std::string que toma un char const*.

Las conversiones estándar ("incorporadas") son preferibles a las conversiones declaradas por el usuario durante la resolución de sobrecarga, por lo que el constructor que toma bool es una mejor coincidencia aquí que la que toma std::string.

Por ahora el único trabajo en torno a que he encontrado es añadir otro constructor

Eso suena como una solución razonable; ciertamente la solución más sencilla para el escenario simple que describes. Sin embargo, su uso de la asignación al *this es un poco torpe; sería mejor tener ambos constructores delegar en alguna función de inicialización.

Alternativamente, se puede utilizar una plantilla con enable_if de ningún constructor para el que no deseas que las conversiones:

template <typename U> 
T(U, std::enable_if<std::is_same<U, bool>::value>::type* = 0) { } 

Este constructor sólo será exigible con un argumento bool y nada más. Puede encontrar enable_if y is_same en Boost, C++ TR1 o C++ 0x. También puede usar !is_pointer, is_integral, o alguna otra combinación de rasgos de tipo para permitir algunos otros tipos de argumentos pero no char const*.

O, como otra alternativa, es posible evitar por completo bool y usar su propia enumeración con enumeradores correspondientes a true y false para el constructor. Si esto tiene sentido depende de su caso de uso.

Declarar explicit T(const bool) para evitar no resuelve el problema anterior ... ¿por qué se forma T t("") todavía se permite y no llamar T(const bool)?

explicit solamente rechaza las conversiones implícitas a T. T t(""); no tiene conversiones a T en absoluto; inicializa directamente el objeto t construyéndolo con el argumento "" pasado a cualquier constructor que coincida mejor.

+0

muchas gracias por la solución con las plantillas – pipex

+0

'enable_if' debe terminar con' ... :: type * = 0'. – UncleBens

+0

@UncleBens: Muchas gracias. Fijo. –

1

"" se puede convertir a std::string y bool.

La pregunta es, ¿de qué manera se convertirá?

  • Conversión a std::string es una conversión definida por el usuario.
  • La conversión a bool es una conversión estándar.

Así que la respuesta es que la conversión estándar tiene mayor prioridad que la conversión definida por el usuario. Entonces "" se convertirá a bool.

ejemplo,

struct A 
{ 
    A(int i) {} //i.e an int can implicity convert to A 
}; 

void f(const A &) { cout << "User-defined conversion won" << endl; } 
void f(const bool &) { cout << "Standard conversion won" << endl; } 

int main() { 
     f (10); 
     return 0; 
} 

de salida:

Standard conversion won 

Demostración en línea: http://www.ideone.com/5Bt0K

En la demo anteriormente, 10 se puede convertir en A y bool ambos. Dado que la conversión a bool es una conversión estándar, se convierte en bool, en lugar de A.

0

Porque no se considera una conversión definida por el usuario si está disponible una integrada.

Utilice el tercer constructor, uno que tome const char*. No hay mejor manera.

+0

"No hay mejor manera". Siento disentir. –

+0

@James McNellis: Su método con 'enable_if' se ve muy bien. –

Cuestiones relacionadas