提问人:dvicino 提问时间:11/5/2015 最后编辑:dvicino 更新时间:11/16/2023 访问量:1043
如何按类型派生过滤可变参数模板包?
How to filter a variadic template pack by type derivation?
问:
我有一个接收多种类型的模板类,收到的每个类型都是两个选项之一的子类。 我想根据标识每个父类以不同的方式扩展它们。这等效于在可变参数模板参数上实现“过滤器”。
例如:
class A{};
class B{};
template<class... C>
struct F{
std::tuple<types_derived_by<A, C>...> fn(types_subclassing<B, C>...){}
};
types_derived_by模板函数应生成一个可变参数模板包,其中包含从 A 或 B 派生的 C 中的所有类型。
例如:
struct DA : public A{};
struct DB : public B{};
int main(){
F<DA, DB> f;
//f has a member function: DA fn(DB);
}
我正在使用 C++11,但如有必要,我可以移动到 c++14。
答:
5赞
Jarod42
11/5/2015
#1
您可以执行以下操作:
template <template <typename> class Pred, typename TUPLE, typename Res = std::tuple<>>
struct Filter;
template <template <typename> class Pred, typename Res>
struct Filter<Pred, std::tuple<>, Res>
{
using type = Res;
};
template <template <typename> class Pred, typename T, typename ... Ts, typename ... TRes>
struct Filter<Pred, std::tuple<T, Ts...>, std::tuple<TRes...>> :
Filter<Pred,
std::tuple<Ts...>,
std::conditional_t<Pred<T>::value,
std::tuple<TRes..., T>,
std::tuple<TRes...>>>
{
};
或者,使用 std::tuple_cat
template <template <typename> class Pred, typename TUPLE>
struct Filter;
template <template <typename> class Pred, typename ... Ts>
struct Filter<Pred, std::tuple<Ts...>>
{
using type = decltype(std::tuple_cat(
std::declval<std::conditional_t<Pred<Ts>::value,
std::tuple<Ts>,
std::tuple<>>>()...));
};
然后:
class A {};
template <typename T>
using is_base_of_A = std::is_base_of<A, T>;
class B {};
struct DA : public A{};
struct DB : public B{};
struct DA1 : public A{};
static_assert(std::is_same<std::tuple<DA, DA1>,
Filter<is_base_of_A, std::tuple<DA, DB, DA1>>::type>::value,
"unexpected");
0赞
Simon Kraemer
11/5/2015
#2
如果您不介意使用元组作为返回值和参数,这可能是适合您的解决方案:
template <typename Base, typename...T>
struct base_filter;
template <typename Base>
struct base_filter<Base>
{
using type = std::tuple<>;
};
template <typename Base, typename T1>
struct base_filter<Base, T1>
{
using type = typename std::conditional_t<std::is_base_of<Base, T1>::value, std::tuple<T1>, std::tuple<>>;
};
template <typename Base, typename T1, typename...T>
struct base_filter<Base, T1, T...>
{
using type = decltype(std::tuple_cat(base_filter<Base, T1>::type(), base_filter<Base, T...>::type()));
};
//###########################################################
class A {};
class B {};
template<class...C>
struct F {
typename base_filter<A, C...>::type fn(typename base_filter<B, C...>::type){}
};
struct DA : public A {};
struct DB : public B {};
struct DA1 : public A {};
struct DA2 : public A {};
struct DB1 : public B {};
struct DB2 : public B {};
int main() {
std::tuple<DB> b;
F<DA, DB> f1;
std::tuple<DA> a = f1.fn(b);
std::tuple<DB1, DB2> bb;
F<DB1, DA1, DB2, DA2> f2;
std::tuple<DA1, DA2> aa = f2.fn(bb);
}
评论
0赞
Piotr Skotnicki
11/5/2015
enable_if_else
看来std::conditional
0赞
Simon Kraemer
11/5/2015
因为它做同样的事情 - 我搜索了类似的东西,但没有找到任何东西。所以我写了我自己的版本。我稍后会调整我的答案。std::conditional
0赞
Simon Kraemer
11/5/2015
@PiotrSkotnicki 调整了我的代码。谢谢你指出来。
评论
std::tuple
typedef ... NearestBase;