SFINAE away a copy constructor

蹲街弑〆低调 提交于 2019-12-06 19:22:57

问题


Under certain conditions, I'd like to SFINAE away the copy constructor and copy assignment operator of a class template. But if I do so, a default copy constructor and a default assignment operator are generated. The SFINAE is done based on tags I pass as class template parameters. The problem is, that SFINAE only works on templates and a copy constructor/assignment operator can't be a template. Does there exist a workaround?


回答1:


This solution uses a base class that is conditionally not copyable (by explicitely marking the copy constructor and copy assignment operator as deleted).

template <bool>
struct NoCopy;

template <>
struct NoCopy<true>
{
   // C++11 and later: marking as deleted. Pre-C++11, make the copy stuff private.
   NoCopy(const NoCopy&) = delete;
   NoCopy& operator=(const NoCopy&) = delete;
   protected:
      ~NoCopy() = default; // prevent delete from pointer-to-parent
};

template <>
struct NoCopy<false>
{
   // Copies allowed in this case
   protected:
      ~NoCopy() = default; // prevent delete from pointer-to-parent
};

Example usage:

template <typename Number>
struct Foo : NoCopy<std::is_integral<Number>::value>
{
   Foo() : NoCopy<std::is_integral<Number>::value>{}
   {
   }
};

int main()
{
   Foo<double> a;
   auto b = a; // compiles fine
   Foo<int> f;
   auto g = f; // fails!
}

Note: the destructor of NoCopy is declared protected to avoid virtual inheritance (Thanks for the hint, @Yakk).




回答2:


The method of deriving from a copyable or non-copyable base is the standard idiom for this type of problem (see also Stefan's comment). One way to implement it is like this:

template<bool> struct copyable
{
protected:
  ~copyable() = default;
};

template<> struct copyable<false> 
{
  copyable(copyable const&) = delete;
  copyable&operator=(copyable const&) = delete;
protected:
  ~copyable() = default;
};

template<bool allow_copy>
class some_class : copyable<allow_copy> { /* ... */ };



回答3:


In C++20, we can use requires-clauses to constrain special member functions:

template <typename T>
class C {
public:
    // ...
    C(const C&) requires std::is_copy_constructible_v<T> // for example
    {
        // ...
    }
    C(C&&) requires std::is_move_constructible_v<T> // for example
    {
        // ...
    }
    // ...
};

A requires-clause does not make the function a function template, so these functions still qualify as special member functions and block the generated default special member functions. You can even have multiple, say, copy constructors, as long as they have different constraints.



来源:https://stackoverflow.com/questions/29430090/sfinae-away-a-copy-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!