簡體   English   中英

您如何在模板 class 中專門化成員 function?

[英]How do you specialize a member function inside a template class?

假設我有以下 class:

template <typename T>
class SomeClass : Parent<T>
{
public:
    // I have a function such as this one:
    T DoSomething(const T &t)
    {
        return t.DoSomething(some_data);
    }

    // But `T` might be a pointer, so sometimes I will need something like the following
    // instead (which obviously doesn't work as given):
    T DoSomething(const T &t)
    {
        return new T(t->DoSomething(some_data));
    }

private:
    XYZ some_data;
};

我陷入了一大堆模板錯誤中,試圖使用模板專業化以任何半好的方式實現這一點。

最后我想出了這個非常丑陋的解決方案:

template <typename T>
class SomeClass : Parent<T>
{
public:
    T DoSomething(const T &x)
    {
        return Specializer<T>::Do(this, x);
    }

private:
    template <typename V>
    struct Specializer {
        static V Do(SomeClass *me, const V &x)
        {
            return x.DoSomething(me->some_data);
        }
    };

    template <typename V>
    struct Specializer<V*> {
        static V* Do(SomeClass *me, const V *&x)
        {
            return new V(x->DoSomething(me->some_data));
        }
    };

    XYZ some_data;
};

有沒有更好的方法來做到這一點,它不涉及將這個 function 填充到一個虛擬類/結構中並傳遞我的this指針?

PS:其實這和指針無關,而是和不同類型的容器有關。 指針只是在這里使用的一個簡單示例。

您可以避免編寫任何特化,並使用std::is_pointer 之類的類型特征以及if constexpr來根據類型是否為指針類型來決定要執行的代碼:

auto DoSomething(const T &t)
{
  if constexpr (std::is_pointer_v<T>)
      return new T(t->DoSomething(some_data));
  else    
      return t.DoSomething(some_data);
}

如果您不想檢查T是否為指針,但想檢查其他內容,您仍然可以通過替換is_pointer來使用此模式。

如果您有權訪問 ,則可以通過使用概念和約束來清除對任何 SFINAE、專業化或if constexpr的需求。 這僅允許您使用不同的實例化標准定義相同的 function N 次,這在 IMO 中更具可讀性。

這與 SFINAE 方法幾乎相同,但不需要糟糕的語法(沒有std::declvaldecltype等)。 它也不像if constexpr方法那樣要求所有實現都存在於一個 function 定義中; 您所需要的只是具有不同requires條款的單獨 function 定義:

#include <concepts>

...

template <typename T>
class SomeClass : Parent<T>
{
public:
    // Work for everything that's not specialized
    void DoSomething(const T &t) 
    { 
        std::cout << "Basic overload" << std::endl; 
    }

    // Only work for pointers
    void DoSomething(const T& t) requires(std::is_pointer_v<T>) 
    { 
        std::cout << "Pointer overload" << std::endl; 
    }

    // Only work if T is convertible to SomeType
    void DoSomething(const T& t) requires(std::convertible_to<T, SomeType>) 
    { 
        std::cout << "Convertible to SomeType overload" << std::endl; 
    }

private:
    XYZ some_data;
};

現場示例

在這種方法中,有 3 個不同的條目:

  • 所有模板的基本后備
  • 適用於任何指針類型的實現,以及
  • 適用於任何可轉換為SomeTypeT類型的實現

使用 SFINAE 怎么樣?

例如

#include <utility>
#include <iostream>

template <typename>
struct Parent
 { };

using XYZ = int;

template <typename T>
class SomeClass : Parent<T>
 {
   public:
      template <typename U = T>
      auto DoSomething (T const & t)
       -> decltype( std::declval<U>().DoSomething(std::declval<XYZ>()) )
        { std::cout << "ref\n"; return t.DoSomething(some_data); }

      template <typename U = T>
      auto DoSomething (T const & t)
       -> std::remove_reference_t<
             decltype( std::declval<U>()->DoSomething(std::declval<XYZ>()),
                       std::declval<T>() )>
        {
          using V = std::remove_reference_t<decltype(*t)>;

          std::cout << "pnt\n"; return new V(t->DoSomething(some_data));
        }

   private:
      XYZ some_data;
 };

struct foo
 {
   foo (foo*) {}
   foo () {}

   foo DoSomething (int) const { return {}; }
 } ;

int main()
 {
   SomeClass<foo>   sc1;
   SomeClass<foo*>  sc2;

   foo f;

   sc1.DoSomething(f);
   sc2.DoSomething(&f);
 }

我的意思是:當且僅當T是支持DoSomething(XYZ)方法的類型並啟用第二個版本時且僅當T是支持DoSomething DoSomething(XYZ)方法?

暫無
暫無

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

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