枚举的模板专业化

问题描述 投票:0回答:1

我有一个通用模板类,我不想(无法)更改它

template <typename TData>
class Printer {
 public:
    bool Write(std::ostream& ostr, const TData& data) const {
        ostr << data;
        return true;
    }
};

我想为

Printer
实现一个专门的类,仅适用于枚举

template <typename TThatIsEnum>
class Printer{
 public:
    bool Write(std::ostream& ostr, const TThatIsEnum& data) const {
        static Printer<int> int_printer;

        return int_printer.Write(ostr, static_cast<int>(data));
    }
};

如果不向通用模板添加额外的模板参数,这可能吗?

c++ templates c++17 template-specialization
1个回答
0
投票

就目前情况而言,在 C++17 中,您没有任何东西可以专门化主模板on。不是可以检测任意类型特征的方式。

标准程序是向主参数添加另一个虚拟参数。

template <typename TData, typename = void>
class Printer {
public:
    bool Write(std::ostream& ostr, const TData& data) const {
        ostr << data;
        return true;
    }
};

它是“内部的”,并不意味着由客户端代码指定。相反,客户端仅指定第一个,模板机制计算出第二个。专业化看起来像这样

template <typename Enum>
class Printer<Enum, std::enable_if_t<std::is_enum_v<Enum>>> {
    Printer<std::underlying_type_t<Enum>> _delegate;
public:
    bool Write(std::ostream& ostr, const Enum& data) const {
        return _delegate.Write(ostr, static_cast<std::underlying_type_t<Enum>>(data));
    }
};

当从客户端的参数中选择专业化时,编译器将实例化特征。对于非枚举

std::enable_if_t<...>
的格式不正确,因此我们回到主要的。它的第二个参数有一个默认参数,因此它可以工作。

对于枚举

std::enable_if_t<...>
将是
void
,因此我们有一个有效的专业化(与主要的可能参数匹配)。我们可以为主要参数提供任意参数(例如
Printer<char, int>
),但并不是每对参数都对我们的专业化有效(
int
永远不会匹配
void
)。另一方面,我们专业化的所有有效参数也将适合主要参数(这就是为什么默认参数是
void
,因此它匹配),因此专业化确实被认为更专业化。

我还冒昧地改进了你的实现,询问枚举的底层类型是什么(而不是假设

int
)。对于库来说,使用成员委托比静态更友好。对象大小相同,但惊喜较少。

最后,您应该知道 C++20 通过类型约束和概念大大简化了这一过程。在 C++20 中我们可以这样写

template <typename TData>
class Printer {
  // As you did
};

template <typename Enum>
  requires std::is_enum_v<Enum>
class Printer {
  // As I did
};

不需要虚拟参数,因为约束成为一等公民。

© www.soinside.com 2019 - 2024. All rights reserved.