sfinae远离析构函数

时间:2016-10-17 20:12:10

标签: c++ c++14 constexpr sfinae

我正在实现与std::vector非常相似的东西,但在堆栈上使用数组而不是内存分配。

d-tor调用使用SFINAE的函数。

  • 如果value_type是POD,则该函数具有空体。
  • 如果value_type是普通类std::string,则该函数会有一个正文并正确销毁所有数据。

现在,我希望能够将这个新的std::vector用作constexpr。然而,即使c-tor被声明为constexpr,代码也不会编译,因为该类具有非平凡的d-tor。

以下是代码的一小部分:

template<typename T, std::size_t SIZE>
class SmallVector{
    constexpr SmallVector() = default;

    ~SmallVector(){
        destructAll_<value_type>();
    }

    // ...

    template<typename X>
    typename std::enable_if<std::is_trivially_destructible<X>::value == true>::type
    destructAll_() noexcept{
    }

};

如果constexpr是POD并且保留非POD数据类型的功能,我可以做些什么来使类成为value_type
(当然不是在同一时间)

2 个答案:

答案 0 :(得分:6)

不幸的是,无法使用SFINAE启用/禁用析构函数,也无法使用未来的概念。那是因为destructos:

  • 无法模板化
  • 不能有参数
  • 不能有返回类型

你可以做的是专门化整个类,或者更好的是,创建一个只包含构造/破坏和基本访问的基类,并将其专门化。

template <class T, class Enable = void>
struct X {
    ~X() {}
};

template <class T>
struct X<T, std::enable_if_t<std::is_pod<T>::value>> {
};

static_assert(std::is_trivially_destructible<X<int>>::value);
static_assert(!std::is_trivially_destructible<X<std::vector<int>>>::value);

答案 1 :(得分:-3)

析构函数中if constexpr的例子。 (需要 C++17)

template<typename Tp, typename TLock>
struct LockedPtr {
private:
    Tp   *m_ptr;
    TLock *m_lk;
    void prelock(std::mutex *mtx) { mtx->lock(); }
    void prelock(std::atomic_flag *atom) { while(atom->test_and_set(std::memory_order_acquire)); }

public:
    LockedPtr(Tp *ptr, TLock *mtx)
    : m_ptr(ptr), m_lk(mtx) {
        prelock(mtx); 
    }

    ~LockedPtr() {
        if constexpr (std::is_same_v<TLock, std::mutex>)
            ((std::mutex *)m_lk)->unlock();
        if constexpr (std::is_same_v<TLock, std::atomic_flag>)
            ((std::atomic_flag *)m_lk)->clear(std::memory_order_release);
    }
};

这些代码是 RAII 锁定智能指针的一部分,通过 std::mutex 来采用普通的 std::atomic_flag 和自旋锁。

  • 使用函数重载来匹配构造函数中的不同类型。
  • 通过 if constexpr 匹配类型并使某些内容无法转换为析构函数中的指针。