如何专门化模板类方法基于类型特征?使用std::enable_if对非类函数有效,但对类方法无效

How to specialize templated class methods based on type traits? Using std::enable_if works for non-class functions, but fails for class methods

本文关键字:类方法 if enable std 类函数 无效 有效 使用 专门化 于类型 特征      更新时间:2023-10-16

我一直在尝试创建模板化类方法的特化,这样我就会有不同的方法定义,编译器根据参数是否为枚举类的整型选择,但是clang给了我这个错误:

'ParseString'的越行定义与'MyData'中的任何声明不匹配

而GCC给出如下:

错误:原型'typename std::enable_if::value, void>::type MyData::ParseString(T&, std::string)'不匹配任何类'MyData'

错误:候选人是:模板静态无效MyData::ParseString(T&, std::string)

下面的代码用于产生这些错误。我已经尝试了使用enable_if的其他方法,比如在模板参数中而不是返回类型中,但到目前为止都没有效果。如果我将模板化的函数设置为非类函数而不是类方法,那么它们就可以正常工作。(去除静电没有影响)

是否有一种方法可以使用enable_if模板化类方法,或者更好的方法来实现同样的事情?

#include <string>
#include <type_traits>
#include <utility>
class MyData
{
public:
    MyData() = default;
    MyData(std::pair<std::string, std::string> string_representations);
    std::pair<std::string, std::string> ToStrings();
    enum class MyEnum
    {
        A = 0,
        B = 1
    };
    int integral_value;
    MyEnum enum_value;
private:
    template<typename T>
    static void ParseString(T&, std::string);
};
MyData::MyData(std::pair<std::string, std::string> string_representations)
{
    ParseString(integral_value, string_representations.first);
    ParseString(enum_value, string_representations.second);
}
std::pair<std::string, std::string> MyData::ToStrings()
{
    return std::make_pair(std::to_string(integral_value), std::to_string((unsigned long)enum_value));
}
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
    MyData::ParseString(T& setting, std::string representation)
{
    setting = (T)std::stoul(representation);
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
    MyData::ParseString(T& setting, std::string representation)
{
    setting = std::stoi(representation);
}

(在本例中,该类只有一个整型和一个枚举成员,但如果您想知道为什么模板化函数会有用,请想象一下,如果该类有多个不同的枚举和整型成员。)

这个错误告诉你,你的ParseString方法定义中的签名不匹配类内部声明中的签名。您必须复制enable_if并在声明中使用它。

template<typename T>
static typename std::enable_if<std::is_integral<T>::value, void>::type ParseString(T&, std::string);

您还需要另一个在声明中使用enable_if<is_enum<T>>ParseString声明,因为您定义了另一个使用它的函数:

template<typename T>
static typename std::enable_if<std::is_enum<T>::value, void>::type ParseString(T&, std::string);