我有以下課程:
template <typename T, int N0, int N1, int N2>
struct A{};
template <typename T, int N0, int N1, int N2>
struct B{};
我希望模板化函式只能采用以下兩種型別之一:
template <typename AorB>
void foo(AorB& arg)
{
}
其中所有 A<T,N0,N1,N2> 和 B<T,N0,N1,N2> 都被接受。解決這個問題的最佳方法是什么?
編輯:這適用于使用繼承的基類。A<...> 會有一些派生類 A_derived<N0, N1, N2>,而 B<...> 會有一些派生類 B_derived<N0, N1, N2>。AorB 如何被限制為 A<...> 或 B<...> 型別?
uj5u.com熱心網友回復:
您可以像這樣定義一個輔助變數:
template<typename T>
constexpr static bool is_ab = false;
template <typename T, int N0, int N1, int N2>
constexpr static bool is_ab<A<T, N0, N1, N2>> = true;
template <typename T, int N0, int N1, int N2>
constexpr static bool is_ab<B<T, N0, N1, N2>> = true;
然后是foo兩者之一的函式is_ab:
template <typename T, std::enable_if_t<is_ab<T>, int> = 0>
void foo(T arg)
{
std::cout << "AB\n";
}
template <typename T, std::enable_if_t<(!is_ab<T>), int> = 0>
void foo(T arg)
{
std::cout << "not AB\n";
}
如果您需要其他型別使用第一個多載,您可以is_ab如圖所示為它們定義。
完整示例在這里。
或者,正如@NathanOliver 所評論的,使用一個概念。
uj5u.com熱心網友回復:
Florestan 的回答最適合您的問題,但我認為這可能是另一種選擇。
#include <utility>
template <auto v>
struct w {};
template <typename T, typename w1, typename w2, typename w3>
struct A {};
template <typename T, typename w1, typename w2, typename w3>
struct B {};
// and derived A, B
template <typename T, typename w1, typename w2, typename w3>
struct DerivedA : public A<T, w1, w2, w3> {};
template <typename T, typename w1, typename w2, typename w3>
struct DerivedB : public B<T, w1, w2, w3> {};
這種方法是因為我不知道如何將型別和非型別模板引數分開。
template <
template <typename... Args> typename Declare,
typename... Arguments_pack
>
constexpr bool is_AorB_type(Declare<Arguments_pack...> type) // separate declare and argument
{
return std::is_same<Declare<Arguments_pack...>, A<Arguments_pack...>>::value
|| std::is_same<Declare<Arguments_pack...>, B<Arguments_pack...>>::value;
}
template <typename AorB>
concept concept_is_AorB_type = (is_AorB_type(*(AorB*)(0)));
template <typename AorB>
requires concept_is_AorB_type<AorB>
void foo(AorB& arg) {}
測驗用
void first_test()
{
constexpr A<int, w<0>, w<0>, w<0>> palk = *(A<int, w<0>, w<0>, w<0>>*)(0);
constexpr bool palk_result = is_AorB_type(palk);
using type2 = std::enable_if<is_AorB_type(palk)>::type;
A<int, w<0>, w<0>, w<0>> a;
B<int, w<0>, w<0>, w<0>> b;
DerivedA<int, w<0>, w<0>, w<0>> da;
DerivedB<int, w<0>, w<0>, w<0>> db;
constexpr bool a_is = is_AorB_type(a); // true
constexpr bool b_is = is_AorB_type(b); // true
constexpr bool da_is = is_AorB_type(da); // false
constexpr bool db_is = is_AorB_type(db); // false
foo(a);
foo(b);
foo(da); // error
foo(db); // error
}
測驗不同的長度
template <typename A, typename B>
struct structs_of_different_lengths{};
void other_test()
{
structs_of_different_lengths<w<0>, w<0>> sdl;
foo(sdl); // error
}
uj5u.com熱心網友回復:
在這種情況下is_ab,實作您想要的一種簡單方法是在基類中定義具有指定名稱的型別,然后將通過 SFINAE 進行測驗。
template <typename T, int N0, int N1, int N2>
struct A{using is_ab = int;};//the type doesn't matter
template <typename T, int N0, int N1, int N2>
struct B{using is_ab = int;};
并測驗我們使用的 is_ab 成員
template<typename T, typename = void> struct is_ab : std::false_type{};
template<typename T> struct is_ab<T, std::void_t<decltype(typename T::is_ab{})>> : std::true_type{};
template<typename T> constexpr bool is_ab_v = is_ab<T>::value;
現在就這么簡單
template <int N0, int N1, int N2>
struct AD: A<int, N0, N1, N2>{};
template <int N0, int N1, int N2>
struct BD: B<int, N0, N1, N2>{};
template<typename T>
auto foo(T& a)
{
static_assert(is_ab_v<T>);
//...
}
int main()
{
A<int,1,2,3> a;
B<bool,3,4,5> b;
AD<3,4,3> ad;
BD<3,2,1> bd;
int r = 4;
foo(a);
foo(b);
foo(ad);
foo(bd);
//foo(r); fail
}
如果您的繼承受到保護/私有并且會觸發斷言,這將不起作用。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/388704.html
