2012-08-17 25 views
6

Tengo el siguiente código que no se compila. Estos son dos funciones en una clase de plantilla que toma los argumentosMétodo de plantilla enable_if especialización

typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { 
    // ... 
} 

typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { 
    // .... 
} 

que quieren tener una especialización en un método de la barra dependiendo de qué tipo es Ret.

¿Alguien tiene alguna idea?

Respuesta

7

SFINAE no funciona en funciones sin plantilla (miembro o no miembro).

Como señala Kerrek SB, las plantillas de funciones no miembro funcionarán. O, como lo señala Xeo, también les servirá crear plantillas de funciones miembro con un argumento de plantilla predeterminado.

Sin embargo, esto solo funciona porque las dos condiciones std::enable_if son sin superposición. Si desea agregar una sobrecarga diferente para int (decir), entonces verá que no se escala tan bien. Dependiendo de lo que quiere hacer, despacho etiqueta generalmente mejor que las escalas SFINAE con múltiples alternativas que desea enviar en:

#include<type_traits> 

template<typename Ret> 
class Foo 
{ 
public: 
    void _on_dispatched() 
    { 
     // tag dispachting: create dummy of either std::false_type or std::true_type 
     // almost guaranteed to be optimized away by a decent compiler 
     helper_on_dispatched(std::is_void<Ret>()); 
    } 

private: 
    void helper_on_dispatched(std::false_type) 
    { 
     // do stuff for non-void 
    } 

    void helper_on_dispatched(std::true_type) 
    { 
     // do stuff for void 
    } 
}; 

int main() 
{ 
    Foo<void>()._on_dispatched(); 
    Foo<int>()._on_dispatched(); 
    return 0; 
} 
+1

Usted puede, si una de las sobrecargas es la única viable en el tiempo de llamada. :) http://liveworkspace.org/code/fd6e5383610d4e0d8fb17c5497991355 – Xeo

+1

@Potatoswatter: En realidad, no, no era una broma. Vea el enlace, puede perfectamente tener una función con exactamente la misma firma donde solo el tipo de devolución decide si es viable. : P Además, solo use 'std :: is_void ()', se requieren rasgos de tipo para derivar de 'std :: true_type' o' std :: false_type'. – Xeo

+1

Por cierto, [puede hacer que el miembro funcione como una plantilla con un parámetro predeterminado en C++ 11] (http://liveworkspace.org/code/781d94df5499998947217970c1aebf2a). – Xeo

3

SFINAE sólo funciona en las plantillas. El código puede ser hecho para compilar con una pequeña modificación:

template <typename Ret> 
typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ } 

template <typename Ret> 
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ } 

Uso:

auto q = _on_dispatched<int>(); 

Por supuesto, puede no deducir el tipo de retorno de una función, ya que no es deducible. Sin embargo, puede empacar dentro de esta plantilla otra plantilla:

template <typename T> 
struct Foo 
{ 
    // insert templates here, maybe privately so 

    T bar() { return _on_dispatched<T>(); } 
}; 
+0

'plantilla ' para las funciones miembro, vea mi comentario en la respuesta de rhalbersma. – Xeo

+0

@Xeo: ¿Quiere decir que nos salvaría de tener que escribir ''? Seguro Por qué no :-) –

Cuestiones relacionadas