2009-09-14 12 views
5

Tengo un problema menor relacionado con los punteros a las funciones de miembro sobrecargadas en C++. El siguiente código compila bien:El operador condicional no puede resolver punteros de función de miembro sobrecargados

class Foo { 
public: 
    float X() const; 
    void X(const float x); 
    float Y() const; 
    void Y(const float y); 
}; 

void (Foo::*func)(const float) = &Foo::X; 

Pero esto no compila (el compilador se queja de que las sobrecargas son ambiguas):

void (Foo::*func)(const float) = (someCondition ? &Foo::X : &Foo::Y); 

de suponer que esto es algo que ver con el compilador de la clasificación de la devolución valor del operador condicional por separado del tipo de puntero a función? Puedo evitarlo, pero estoy interesado en saber cómo funciona la especificación, se supone que todo esto funciona, ya que parece poco intuitivo y si hay alguna forma de evitarlo sin caer en 5 líneas de if-then-else .

Estoy usando MSVC++, si eso hace la diferencia.

Gracias!

+1

Debe indicar qué significa "no funciona". ¿Error del compilador? ¿Comportamiento de tiempo de ejecución inesperado? –

+0

Han hecho eso, gracias por la sugerencia. – Peter

Respuesta

7

Desde la sección 13.4/1 ("Dirección de la función sobrecargada," [over.over]):

Un uso de un nombre de función sobrecargada sin argumentos se resuelve en determinados contextos a una función, un puntero para funcionar o señalar a la función miembro para una función específica del conjunto de sobrecarga. Se considera que un nombre de plantilla de función nombra un conjunto de funciones sobrecargadas en dichos contextos. La función seleccionada es aquella cuyo tipo coincide con el tipo de destino requerido en el contexto. La diana puede ser

  • un objeto o de referencia que se inicializa (8.5, 8.5.3),
  • el lado izquierdo de una asignación (5,17),
  • un parámetro de una función (5.2.2) ,
  • un parámetro de un operador definido por el usuario (13.5),
  • el valor de retorno de una función, la función de operador, o la conversión (6.6.3), o
  • una conversión de tipo explícita (5.2.3, 5.2.9, 5.4).

El nombre de la función de sobrecarga puede ir precedido por el operador &. Un nombre de función sobrecargado no se utilizará sin argumentos en contextos distintos a los enumerados. [Nota: se ignora cualquier conjunto redundante de paréntesis que rodean el nombre de la función sobrecargada (5.1). ]

El objetivo usted esperaba sería seleccionado de la lista anterior fue el primero, un objeto que se ha inicializado. Pero hay un operador condicional en el camino, y los operadores condicionales determinan sus tipos a partir de sus operandos, no de ningún tipo de destino.

Dado que las conversiones de tipo explícito se incluyen en la lista de objetivos, puede escribir de forma independiente cada expresión de puntero de miembro en la expresión condicional. Me gustaría hacer un typedef primera:

typedef void (Foo::* float_func)(const float); 
float_func func = (someCondition ? float_func(&Foo::X) : float_func(&Foo::Y)); 
+0

Gracias, eso funciona perfectamente, justo lo que estaba esperando. – Peter

1

Ejemplo:

class Foo { 
public: 
    void X(float x) {} 
    void Y(float y) {} 
    float X() const; 
}; 
typedef void (Foo::*Fff)(float); 
Fff func = &Foo::X; 
Fff func2 = true ? (Fff)&Foo::X : (Fff)&Foo::Y; 

int main(){ 
    return 0; 
} 

Es necesario echar & Foo :: X de inmediato con el fin de resolver la sobrecarga. Tenga en cuenta que si comenta la flotación X() sobrecargada, no es necesario que lo haga.

Parece que el compilador no es lo suficientemente inteligente como para inferir el tipo de retorno requerido de una expresión ternaria (esto puede ser un error).

+0

someCondition no es una constante en tiempo de compilación, aunque eso probablemente no era totalmente obvio a partir del ejemplo simplificado que proporcioné. Posiblemente podría convertirlo en uno mediante la creación de plantillas, pero creo que sería más feo en general ... :) – Peter

+1

No es necesario que sea uno, de todos modos. –

1

Probar:

void (Foo::*func1)(const float) = &Foo::X; 
    void (Foo::*func2)(const float) = &Foo::Y; 

    void (Foo::*func3)(const float) = (someCondition ? func1:func2); 

El problema es el tipo de resultado del operador ternario está determinada por sus argumentos.
En esta situación, no puede determinar el tipo de resultado porque los tipos de entrada tienen opciones múltiples. No es hasta que se haya determinado que el tipo del operador trinario intentará la asignación.

Cuestiones relacionadas