[英]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
來使用此模式。
如果您有權訪問c++20 ,則可以通過使用概念和約束來清除對任何 SFINAE、專業化或if constexpr
的需求。 這僅允許您使用不同的實例化標准定義相同的 function N 次,這在 IMO 中更具可讀性。
這與 SFINAE 方法幾乎相同,但不需要糟糕的語法(沒有std::declval
、 decltype
等)。 它也不像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 個不同的條目:
SomeType
的T
類型的實現使用 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.