首先,是否有可能根据某些条件返回不同的类型?其次,是否有一种更简洁的方式来处理这种映射,而无需枚举所有可能的if和else?
这里有很多(很多)的if,and和but
基本上,我想定义一个不完整的元组,我希望将其自动扩展以完成某些默认类型。当然,完整性与某些上下文有关。在此,B0和B1将是默认值。并且完整的元组必须具有形式<B0 or its derived, B1 or its derived>
。实际上,我工作中的元组具有两个以上的元素。
struct B0 { };
struct B1 { };
// here, a complete tuple is a tuple that has two elements:
// of B0 type or its derived as a 1st element and
// of B1 type or its derived as a 2nd element
// templ argumets can be in the order B0, B1 or its derived or absent
template<class Tuple>
CompleteTuple make_complete_tuple()
{
if (std::tuple_size<Tuple>::value == 0)
return std::tuple<B0,B1>{};
else if (std::tuple_size<Tuple>::value == 1)
{
using ElemT = std::tuple_element<0, Tuple>::type;
if (std::is_base_of<B0, ElemT>::value)
return std::tuple<ElemT, B1>{};
if (std::is_base_of<B1, ElemT>::value)
return std::tuple<B0, ElemT>{};
}
else if (std::tuple_size<Tuple>::value == 2)
{
using Elem0T = std::tuple_element<0, Tuple>::type;
using Elem1T = std::tuple_element<1, Tuple>::type;
if (std::is_base_of<B0, Elem0T>::value)
if(std::is_base_of<B1, Elem1T>::value)
return std::tuple<Elem0T, Elem1T>{};
// not handling another conditions, the example is only for conveying idea
}
}
struct A : public B0 { };
struct C : public B1 { };
int main()
{
auto complete_tuple0 = make_complete_tuple<std::tuple<A>>();
// complete_tuple0 shoud be std::tuple<A, B1>;
auto complete_tuple1 = make_complete_tuple<std::tuple<C>>();
// complete_tuple1 shoud be std::tuple<B0, C>;
// etc
std::cin.get();
return 0;
}
C ++ 17解决方案,如果用替换_v
usings
为C ++ 11 ::value
。不需要不同的基数,但是它将始终用传递的元组参数中最左边的匹配类型替换默认元组中的每个默认基数。
#include <tuple>
#include <type_traits>
// Returns the first type from Ts that is derived from Base. Returns Base if there is not one.
template<typename Base,typename...Ts>
struct pick_derived;
// No Ts were derived from Base.
template<typename Base>
struct pick_derived<Base>{
using type=Base;
};
template<typename Base,typename Derived, typename...Tail>
struct pick_derived<Base,Derived,Tail...>{
using type = typename std::conditional<std::is_base_of_v<Base,Derived>,
Derived,// Return it. Otherwise continue searching.
typename pick_derived<Base,Tail...>::type>::type;
};
template<typename SourceTuple, typename DefaultTuple>
struct tup_transformer_impl;
template<typename...Ts, typename...Ds>
struct tup_transformer_impl<std::tuple<Ts...>,std::tuple<Ds...>>{
// Fancy double pack expansion
// For each default Ds type, try to replace it with a derived type from Ts.
using type = std::tuple<typename pick_derived<Ds,Ts...>::type...>;
};
#include <iostream>
struct B0 { };
struct B1 { };
// Tweak this.
using default_tuple = std::tuple<B0,B1>;
template<typename Tuple>
using tup_transform = typename tup_transformer_impl<Tuple,default_tuple>::type;
template<class Tuple>
tup_transform<Tuple> make_complete_tuple()
{
return {};
}
struct A : public B0 { };
struct C : public B1 { };
int main()
{
auto complete_tuple0 = make_complete_tuple<std::tuple<A>>();
// complete_tuple0 shoud be std::tuple<A, B1>;
static_assert(std::is_same_v<decltype(complete_tuple0),std::tuple<A, B1>>);
auto complete_tuple1 = make_complete_tuple<std::tuple<C>>();
// complete_tuple1 shoud be std::tuple<B0, C>;
static_assert(std::is_same_v<decltype(complete_tuple1),std::tuple<B0, C>>);
std::cin.get();
return 0;
}
我猜你可以这样称呼它:
tup_transform<std::tuple<A>> complete_tuple0;
(将其更改tup_transform<A> complete_tuple0;
为非常容易。只需将tup_transformer_impl更改为Ds...
直接使用即可,而不是解压缩它们。)
当然,所有这些都要求每种类型都是默认可构造的。如果不是这种情况,我认为如果派生类型至少是可移动的,则该解决方案可以适用。在这种情况下,每个派生值都必须传递给make_complete_tuple
函数。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句