¿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.
muchas gracias por la solución con las plantillas – pipex
'enable_if' debe terminar con' ... :: type * = 0'. – UncleBens
@UncleBens: Muchas gracias. Fijo. –