关于模板 class 专业化的范例

Paradigm regarding template class specialization

我目前正在编写一个模板 class 用于归档(或序列化)和取消归档数据 into/from 二进制格式。首先,我试图结束我将使用的模式。我主要倾向于使用模板,因为 unarchiver 没有用于方法重载的输入类型。例如,下面的例子是可以的:

Archiver ar;
int i;

archive(ar, i);

但它的对应物不是:

Unarchiver unar;
int i;

i = unarchive(unar);

我想避免使用函数名,例如unarchive_int,因为使用模板时会很麻烦。说:

template <class T> class SomeClass
{
public:

   void doSomething()
   {
      // Somewhere
      T value = unarchive(unar);
   }
};

这会使事情变得混乱,因此我宁愿为此使用模板,而之前的表达式是 T value = unarchive<T>(ar);。如果第一个或唯一的参数总是归档器和非归档器对象,那么编写一个全局函数似乎也很愚蠢(可以说);模板 class 似乎是有序的:

template <class T> class Archiver
{
public:

    void archive(T obj);
};

这可行,但归档方法总是复制其输入对象。这对于 POD 数据类型是可以的,但 classes 就不行了。解决方案似乎很明显,而是像 void archive(const T & obj) 中那样使用 const 引用,但现在通过引用传递整数、浮点数和其他 PODs 似乎也很愚蠢。虽然我对这个解决方案很满意,但我尝试更进一步,让对象做出区分。我的第一种方法是 std::enable_if,默认情况下假设一个副本(对于所有非 class 成员)并提供 class 专业化,其中 archive 方法通过引用获取其输入反而。它不起作用。这是代码:

template <class T, class E = void>
class Archiver
{
public:

    // By default, obj is passed by copy
    void archive(T obj);
};

template <class T>
class Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::value>
{
public:

    // I would expect this to be used instead if is_class<T> && !is_pod<T>
    void archive(const T & obj);
};

问题是编译器根本看不到第二个声明,证据如下:

template <> void Archiver<std::uint8_t>::archive(uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);

前者编译正常,但后者给出:

out-of-line declaration of 'archive' does not match any declaration in 'Archiver<std::__1::basic_string<char>, void>'

另一方面,如果我得到 std::string 而不是通过 copy if 编译就好了。我想我知道为什么会这样,编译器选择第一个模板,因为它对两个声明都足够通用,但是我如何让它选择更专业的版本?

你想要std::enable_if<...>::type std::enable_if<...>::value

Here's a full demo:

#include <type_traits>
#include <cstdint>
#include <string>

template <class T, class E = void>
struct Archiver {
    void archive(T obj);
};

template <class T>
struct Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::type>
{
    void archive(const T & obj);
};

template <> void Archiver<std::uint8_t>::archive(std::uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);

IIUC,问题归结为如何定义为调用函数优化的通用模板类型。

为此,您可以考虑 boost::call_traits,特别是 param_type:

template<typename T>
void foo(typename boost::call_traits<T>::param_type t);