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

Using SFINAE to resolve allocator member conditionally

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

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

...
}

class 采用 Allocator 模板参数,如果提供 none,则默认为 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_') 提供?

谢谢

您的问题是在 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::is_same 测试为假时也会编译 std::cout << alloc.member_

因此,您必须以某种方式开发两种不同的功能:一种用于 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); }