Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sfinae away a destructor

I am implementing something very similar to std::vector but uses array on the stack instead of memory allocation.

The d-tor calls a function that uses SFINAE.

  • If value_type is POD the function have empty body.
  • If value_type is normal class such std::string, the function have a body and destroy all the data properly.

Now, I want to be able to use this new std::vector as constexpr. However even the c-tor is declared constexpr, the code does not compiles because the class have non trivial d-tor.

Here is small part of the code:

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{
    }

};

Is there anything I can do to make class be constexpr if value_type is POD and keeping functionality for non POD data types.
(Not at the same time of course)

like image 756
Nick Avatar asked Oct 17 '16 20:10

Nick


1 Answers

until C+20

Unfortunately, there is no way to enable/disable destructor with SFINAE, nor with future concepts. That is because destructos:

  • can't be templated
  • can't have arguments
  • can't have a return type

What you can do is specialize whole class, or better yet, create a base class that contains only the construct/destruct and basic access and specialize that.

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);

C++ 20

As far as I can tell you can constraint a destructor and get exactly what you want in a very simple and elegant solution:

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

    ~SmallVector() requires std::is_trivially_destructible_v<T> = default;

    ~SmallVector()
    {   
    }
};

static_assert(std::is_trivially_destructible_v<SmallVector<int, 4>>);
static_assert(!std::is_trivially_destructible_v<SmallVector<std::string, 4>>);

However this is a brand new feature and there have been some changes lately (e.g. see Disable non-templated methods with concepts) and the compiler support is still sketchy. gcc compiles this just fine, while clang is confused by the fact that there are two definitions of the destructor godbolt

like image 200
bolov Avatar answered Sep 19 '22 13:09

bolov