使用SFINAE有条件地解析分配器成员

时间:2018-06-29 07:43:08

标签: c++ c++11 templates sfinae

我正在为列表数据结构编写一个构造函数。

template <class T, class Allocator = std::allocator<T>>
class list {

...
}

该类采用Allocator模板参数,如果未提供,则默认为std::allocator。由于C ++ 11分配器可能具有状态,因此默认构造函数也采用了分配器对象。

//    *** CONSTRUCTORS ***
explicit list(const Allocator& alloc = Allocator()): alloc_(alloc), head_(nullptr), tail_(nullptr), size_(0) {
    if(std::is_same<Allocator, customAllocator<T>>::value) {
        std::cout << "****" << std::endl;
        std::cout << alloc.member_ << std::endl;
        std::cout << alloc_.member_ << std::endl;
        std::cout << "****" << std::endl;
    }
}

提供包含“ member_”的自定义分配器时,以下几行将成功执行。

但是,当传递std::allocator时,编译器会抱怨说分配器中没有成员'member_'。

但是,有一种方法可以使std::cout行在提供自定义分配器时打印,而在std::allocator(或任何不带'member_'的分配器时不打印) )提供了吗?

谢谢

1 个答案:

答案 0 :(得分:2)

您的问题是在C ++ 17中引入的一个典型问题if constexpr

 if constexpr (std::is_same<Allocator, customAllocator<T>>::value) {
    std::cout << "****" << std::endl;
    std::cout << alloc.member_ << std::endl;
    std::cout << alloc_.member_ << std::endl;
    std::cout << "****" << std::endl;
}

在C ++ 17之前,if constexpr不可用,因此当std::cout << alloc.member_测试为假时,std::is_same也会被编译。

因此,您必须以某种方式开发两个不同的功能:一个用于customAllocator,另一个用于其他功能。

我想您可以尝试以下操作(警告:未测试代码)

   template <typename T>
   void printMember (customAllocator<T> const & a)
    { 
      std::cout << "****" << std::endl;
      std::cout << alloc.member_ << std::endl;
      std::cout << alloc_.member_ << std::endl;
      std::cout << "****" << std::endl;
    }

   template <typename A>
   void printMember (A const &)
    { }

   explicit list(const Allocator& alloc = Allocator())
      : alloc_(alloc), head_(nullptr), tail_(nullptr), size_(0)
    { printMember(alloc); }

如果需要,还可以为具有member_成员的分配器和为其他成员的分配器编写一个函数。

以下内容(警告:代码未经测试)

   template <typename A>
   auto printMember (A const & a, int)
      -> decltype( a.member_, void() )
    { 
      std::cout << "****" << std::endl;
      std::cout << alloc.member_ << std::endl;
      std::cout << alloc_.member_ << std::endl;
      std::cout << "****" << std::endl;
    }

   template <typename A>
   void printMember (A const &, long)
    { }

   explicit list(const Allocator& alloc = Allocator())
      : alloc_(alloc), head_(nullptr), tail_(nullptr), size_(0)
    { printMember(alloc, 0); }