Tengo problemas al intentar especializar un método de plantilla de una clase para aceptar una clase derivada. También lo intenté con punteros y terminé con muchos más problemas que esta iteración.

#include <iostream>

using namespace std;

class Json {
  public:
    Json(){}
    virtual ~Json(){}
    template <class T>
    bool Get(std::string key, T& value);
};

template <class T>
bool Json::Get(std::string key, T& value){
    std::cout << "Call default GET" << std::endl;
}

template <>
bool Json::Get(std::string key, Json& value){
    std::cout << "Call JSON GET" << std::endl;
}

class JsonError : public Json {
    public:
        JsonError(){}
        ~JsonError(){}
};

int main()
{
    // OK
    int int_value = 0;
    Json json;
    json.Get("int", int_value);
    
    // OK
    Json json_value;
    json.Get("json", json_value);
    
    // NOT OK
    JsonError json_error_value;
    json.Get("error", json_error_value);
    
    return 0;
}

Esto debería imprimir

Call default GET                                                                                                                                            
Call JSON GET                                                                                                                                               
Call JSON GET  
2
ony_pox232 26 ago. 2020 a las 17:40

1 respuesta

La mejor respuesta

No es así como funcionan las plantillas. La deducción de la plantilla siempre es del tipo exacto, en este caso JsonError, por lo que la especialización de Json& no coincide.

Si aún desea que funcione, puede sobrecargar la función de plantilla con una función miembro que tome Json&. La función de plantilla seguirá siendo una mejor coincidencia para un tipo derivado, por lo que también necesitamos deshabilitar el método de plantilla para cualquier tipo que se derive de Json.

#include <iostream>

class Json {
  public:
    Json(){}
    virtual ~Json(){}
    template <class T, std::enable_if_t<!std::is_base_of_v<Json, T>, int> = 0>
    bool Get(std::string key, T& value);

    bool Get(std::string key, Json& value);
};

template <class T, std::enable_if_t<!std::is_base_of_v<Json, T>, int> = 0>
bool Json::Get(std::string key, T& value){
    std::cout << "Call default GET" << std::endl;
    return true;
}

bool Json::Get(std::string key, Json& value){
    std::cout << "Call JSON GET" << std::endl;
    return true;
}

class JsonError : public Json {
    public:
        JsonError(){}
        ~JsonError(){}
};

int main()
{
    // OK
    int int_value = 0;
    Json json;
    json.Get("int", int_value);
    
    // OK
    Json json_value;
    json.Get("json", json_value);
    
    // NOW IT'S OK
    JsonError json_error_value;
    json.Get("error", json_error_value);
    
    return 0;
}
3
super 26 ago. 2020 a las 14:55