各种集合的模板类部分特化

时间:2016-03-12 15:36:50

标签: c++ templates c++11 template-specialization

我试图编写2个模板部分特化,它们应该以不同方式序列化序列容器和关联容器,但似乎根本没有使用序列容器特化,因为编译器试图将其专门化。错误的专业化,这里是代码:

template<typename W, typename T, template<typename...> class C, typename... Args>
class Archiver<W, C<T, Args...>>
{
public:
  template<typename U = C<T, Args...>, typename std::enable_if<std::is_same<typename U::value_type, T>::value, int>::type = 0>
  static void serialize(const W& w, const C<T, Args...>& container)
  {
    ...
  }

  template<typename U = T, typename std::enable_if<!std::is_base_of<archive::require_placement_move, U>::value, int>::type = 0,
  typename J = C<T,Args...>, typename std::enable_if<std::is_same<typename J::value_type, T>::value, int>::type = 0>
  static void unserialize(const W& r, const Context& c, C<T,Args...>& container)
  {
    ...
  }

  template<typename U = T, typename std::enable_if<std::is_base_of<archive::require_placement_move, U>::value, int>::type = 0,
  typename J = C<T,Args...>, typename std::enable_if<std::is_same<typename J::value_type, T>::value, int>::type = 0>
  static void unserialize(const W& r, const Context& c, C<T,Args...>& container)
  {
    ...
  }
};

template< typename W, typename K, typename T, template<typename...> class M, typename... Args>
class Archiver<W, M<K, T, Args...>>
{
public:
  template<class U = M<K,T,Args...>, typename std::enable_if<std::is_same<typename U::key_type, K>::value && std::is_same<typename U::mapped_type, T>::value, int>::type = 0>
  static void serialize(const W& w, const M<K,T,Args...>& container)
  {
    ...
  }

  template<class U = M<K,T,Args...>, typename std::enable_if<std::is_same<typename U::key_type, K>::value && std::is_same<typename U::mapped_type, T>::value, int>::type = 0>
  static void unserialize(const W& r, const Context& c, M<K,T,Args...>& container)
  {
    ...
  }
};

如果我尝试使用

Writer w;
Archiver<Writer, std::list<float>>::serialize(...);

决议是在第二次专业化时完成的,从而导致了

  

Candidate template ignored: substitution failure [with U = std::__1::list<float, std::__1::allocator<float> >]: no type named 'key_type' in 'std::__1::list<float, std::__1::allocator<float> >'

这应该意味着第一个专业化被排除在先验之前,就像扣除解决方案是选择与地图相关的一个。或者也许我错过了一些非常愚蠢的东西,因为我从一段时间开始研究这段代码。

1 个答案:

答案 0 :(得分:1)

我认为您对SFINAE的使用有点偏。

您正在Archive模板中明确指定容器类型。一些未知的C ++规则意味着在传递std::list<float>时会选择第二个特化。 SFINAE 然后应用于serialize函数,消除了可用的重载(因此错误消息)。由于已选择Archive的第二个特化,因此第一个特化中的serialize函数从未被视为。这不是你想要的。

由于您明确指定了容器类型,因此我不确定您为什么要尝试使用SFINAE。要为序列和关联容器分别进行适当的专门化,您可能需要等到概念标准化。在那之前,你可以做一些天真的事情,比如基于类别别名key_type的存在而进行专门化(这是你已经在做的事情)。

以下是一个例子:

#include <type_traits>

template<typename>
using void_t = void;

template<typename T, typename = void>
struct has_key_type : std::false_type
{
};

template<typename T>
struct has_key_type<T, void_t<typename T::key_type>> : std::true_type
{
};

template<typename C, typename = std::enable_if_t<has_key_type<C>::value>>
void serialize(C const& c)
{
};

template<typename C, typename = std::enable_if_t<!has_key_type<C>::value>, typename = void>
void serialize(C const& c)
{
};

#include <iostream>
#include <list>
#include <map>

int main()
{
  serialize(std::list<int>());
  serialize(std::map<float, float>());
}