C++ c++;带有派生类的模板专门化

C++ c++;带有派生类的模板专门化,c++,templates,C++,Templates,我在尝试专门化类的模板方法以接受派生类时遇到问题。我也尝试过使用指针,但最终遇到的问题比这次迭代多得多 #include <iostream> using namespace std; class Json { public: Json(){} virtual ~Json(){} template <class T> bool Get(std::string key, T& value); }; template <

我在尝试专门化类的模板方法以接受派生类时遇到问题。我也尝试过使用指针,但最终遇到的问题比这次迭代多得多

#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;
}

模板不是这样工作的。模板推断总是精确的类型,在本例中是
JsonError
,因此
Json&
的专门化不匹配

如果您仍然想让它工作,您可以使用一个成员函数重载模板函数,该函数采用
Json&
。对于派生类型,模板函数仍然是一个更好的匹配,因此我们还需要对从
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;
}
#包括
类Json{
公众:
Json(){}
虚拟~Json(){}
模板=0>
bool-Get(标准::字符串键,T和值);
bool-Get(std::字符串键、Json和值);
};
模板=0>
booljson::Get(std::字符串键、T和值){

std::cout模板类型推断的参数总是比需要任何隐式强制转换的参数更精确(例如
JsonError&
Json&
),因此在重载解析过程中总是会被解析为更好的重载。您可以解决这一问题,但重新思考所需的APICannot REPLACTION可能会更容易:您使用的是什么编译器和版本?@人工编译器在这里没有出现。
t
被推断为
JsonError
,这意味着n for
Json
不被使用,默认模板被调用,至少在一致性编译器中是这样。@NathanOliver我认为OP意味着所需的输出是
Json GET
,但程序不是这样做的。@NathanOliver OP希望最后一次调用打印
call Json GET
,没有错误,但最后一次调用的当前输出是正确的是
Call default GET
我没有访问C++11的权限,但这是一个很酷的答案。@ony_pox232实际上asnwer中的代码使用C++17,但在C++11中没有不能完成的操作。对于与当前标准无关的问题,最好使用该标准特定版本的标记
#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;
}