簡體   English   中英

C++ 條件模板構造函數

[英]C++ Conditional template constructor

我有一個類似於智能指針的HandleID class。 以下是重要的部分:

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

現在我希望能夠從 HandleID<T> 構造一個HandleID<const T> HandleID<T>而不是相反。 復制賦值運算符也是如此: HandleID<const T> = HandleID<T>應該是合法的,但不是HandleID<T> = HandleID<const T>

現在我考慮為此添加模板專業化或其他東西,但我確信有更好的方法來做到這一點。 請注意,非 const 版本必須將 const 版本添加為友元,才能訪問構造函數/assignmnent 運算符中的私有成員。

SFINAE 方式...

為簡化起見,您可以為無常量T添加using類型

using no_const_T = std::remove_const_t<T>;

T不是const時等於T ,當Tconst時不同。

然后,您可以僅在Tno_const_T不同時啟用 SFINAE 構造函數/運算符

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

請注意,您必須檢查T是否與no_const_T相等或不同,而不是直接使用T而是使用用T初始化的本地(方法)模板參數( U )。

- 編輯 -

OP問

當我想將聲明(您提供的那個)和實現(例如在文件中進一步向下的 class 之外)分開時,語法是什么

這是一種譫妄。

以下是在 class 主體之外實現的啟用 SFINAE 的方法的完整編譯(愚蠢)示例。

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

在 C++20 中,它將是:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM