And*_*lli 2 c++ templates template-specialization c++11
我目前正在编写一个模板类,用于存档(或序列化)和从二进制格式中取消存档数据.首先,我试图关闭我将使用的模式.我主要倾向于使用模板,因为unarchivers没有方法重载的输入类型.例如,以下示例是正常的:
Archiver ar;
int i;
archive(ar, i);
Run Code Online (Sandbox Code Playgroud)
但它的对手不是:
Unarchiver unar;
int i;
i = unarchive(unar);
Run Code Online (Sandbox Code Playgroud)
我想避免使用函数的名称,例如unarchive_int因为使用模板时会很麻烦.说:
template <class T> class SomeClass
{
public:
void doSomething()
{
// Somewhere
T value = unarchive(unar);
}
};
Run Code Online (Sandbox Code Playgroud)
这会使事情变得混乱,因此我真的使用模板,而前一个表达式将是T value = unarchive<T>(ar);.如果第一个或唯一的参数始终是archiver和unarchiver对象,那么写一个全局函数似乎也很愚蠢(可以说); 模板类似乎是有序的:
template <class T> class Archiver
{
public:
void archive(T obj);
};
Run Code Online (Sandbox Code Playgroud)
这样可行,但归档方法始终复制其输入对象.对于POD数据类型,这是可以的,但不是那么多类.解决方案似乎很明显,而是使用const引用void archive(const T & obj),但现在通过引用传递整数,浮点数和其他POD似乎也很愚蠢.虽然我对这个解决方案感到满意,但我还是试着进一步让对象做出区分.我的第一种方法是std::enable_if,默认情况下假设一个副本(对于所有非类成员)并提供类特化,其中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);
};
Run Code Online (Sandbox Code Playgroud)
问题是第二个声明对编译器根本不可见,这里有证据:
template <> void Archiver<std::uint8_t>::archive(uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
Run Code Online (Sandbox Code Playgroud)
前者编译好,但后者给出:
"档案"的外线声明与任何声明都不符
'Archiver<std::__1::basic_string<char>, void>'
另一方面,如果我std::string通过副本获得,如果编译就好了.我想我知道为什么会发生这种情况,编译器会选择第一个模板,因为它对于两个声明都足够通用,但是如何让它选择更专业的版本呢?
你想std::enable_if<...>::type,没有 std::enable_if<...>::value.
#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);
Run Code Online (Sandbox Code Playgroud)