简体   繁体   中英

C++ Conditional template constructor

I have a HandleID class that acts similar to a smart pointer. Here are the important bits:

template<class T>
class HandleID
{
// Only if T is not const
friend class HandleID<const T>;

public:
    HandleID();
    HandleID(int id);
    HandleID(const HandleID<T>& other);
    HandleID& operator=(const HandleID<T>& other);

    // Only if T is const
    HandleID(const HandleID<const removed T>& other);
    HandleID& operator=(const HandleID<const removed T>& other);


private:
    T* cachedPointer;
    int id;
};

Now I want to be able to construct a HandleID<const T> from a HandleID<T> but not the other way around. The same for the copy assignment operator: HandleID<const T> = HandleID<T> should be legal but not HandleID<T> = HandleID<const T> .

Now I thought about adding a template specialization or something for this but I'm sure there is a nicer way of doing this. Note that the non-const version must add the const version as a friend for it to be able to access the private members in the constructor / assignmnent operator.

The SFINAE way...

To simplify, you can add a using type for the no-const T

using no_const_T = std::remove_const_t<T>;

that is equal to T when T isn't const , different when T is const .

Then you can SFINAE enable your constructor/operator only when T and no_const_T are different

template <typename U = T,
          std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
HandleID(const HandleID<no_const_T> & other);

template <int..., typename U = T, 
          std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
HandleID& operator=(const HandleID<no_const_T>& other);

Observe that you have to check that T is equal or different to no_const_T not using directly T but a local (to the method) template parameter ( U ) that is initialized with T .

-- EDIT --

The OP ask

what is the syntax when I want to separate the declaration (The one you provided) and the implementation (eg outside the class further down in the file)

It's a delirium.

The following is a full compiling (silly) example whit SFINAE enabled method implemented outside the body of the class.

#include <type_traits>

template <typename T>
class HandleID
 {
   friend class HandleID<T const>;

   using no_const_T = std::remove_const_t<T>;

   public:
      HandleID () {}
      HandleID (int) {}
      HandleID (HandleID<T> const &) {}

      template <typename U = T,
                std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
      HandleID (HandleID<no_const_T> const &);

      HandleID & operator= (HandleID<T> &)
       { return *this; }

      template <int..., typename U = T,
                std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
      HandleID & operator= (HandleID<no_const_T> const &);
 };

template <typename T>
template <typename U,
          std::enable_if_t<not std::is_same_v<U,
             std::remove_const_t<T>>, int>>
HandleID<T>::HandleID (HandleID<std::remove_const_t<T>> const &)
 { }

template <typename T>
template <int..., typename U,
          std::enable_if_t<not std::is_same_v<U,
             std::remove_const_t<T>>, int>>
HandleID<T> & HandleID<T>::operator=
   (HandleID<std::remove_const_t<T>> const &)
 { return *this; }

int main()
 {
   HandleID<int>       id0;
   HandleID<int const> idc0;

   HandleID<int>  id1{id0};  // copy constructor: compile
   //HandleID<int>  id2{idc0}; // constructor disabled: compilatrion error

   HandleID<int const>  idc1{idc0};  // copy constructor: compile
   HandleID<int const>  idc2{id0};   // constructor enabled: compile
 }

In C++20, it would be:

template<class T>
class HandleID
{
friend class HandleID<const T>;

public:
    HandleID();
    HandleID(int id);
    HandleID(const HandleID<T>& other);
    HandleID& operator=(const HandleID<T>& other);

    HandleID(const HandleID<std::remove_const_t<T>>& other) requires (std::is_const_v<T>);
    HandleID& operator=(const HandleID<std::remove_const_t<T>>& other) requires (std::is_const_v<T>);

private:
    T* cachedPointer;
    int id;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM