如何从元组C 过滤重复类型
How to filter duplicate types from tuple C++
一个人如何从元组中进行滤波?
例如:
using Tuple = std::tuple<int, double, int, double, std::string, std::string>
using FilteredTuple = without_duplicates<Tuple>;
在其中实现没有_duplicates的方式以生成以下过滤器类型的方式:
std::tuple<int, double, std::string>
#include <type_traits>
#include <tuple>
template <typename T, typename... Ts>
struct unique : std::type_identity<T> {};
template <typename... Ts, typename U, typename... Us>
struct unique<std::tuple<Ts...>, U, Us...>
: std::conditional_t<(std::is_same_v<U, Ts> || ...)
, unique<std::tuple<Ts...>, Us...>
, unique<std::tuple<Ts..., U>, Us...>> {};
template <typename... Ts>
using unique_tuple = typename unique<std::tuple<>, Ts...>::type;
demo
这应该有效:
template <class Haystack, class Needle>
struct contains;
template <class Car, class... Cdr, class Needle>
struct contains<std::tuple<Car, Cdr...>, Needle> : contains<std::tuple<Cdr...>, Needle>
{};
template <class... Cdr, class Needle>
struct contains<std::tuple<Needle, Cdr...>, Needle> : std::true_type
{};
template <class Needle>
struct contains<std::tuple<>, Needle> : std::false_type
{};
template <class Out, class In>
struct filter;
template <class... Out, class InCar, class... InCdr>
struct filter<std::tuple<Out...>, std::tuple<InCar, InCdr...>>
{
using type = typename std::conditional<
contains<std::tuple<Out...>, InCar>::value
, typename filter<std::tuple<Out...>, std::tuple<InCdr...>>::type
, typename filter<std::tuple<Out..., InCar>, std::tuple<InCdr...>>::type
>::type;
};
template <class Out>
struct filter<Out, std::tuple<>>
{
using type = Out;
};
template <class T>
using without_duplicates = typename filter<std::tuple<>, T>::type;
[LIVE示例]
[Godbolt]
它通过迭代构建输出元组来起作用。在添加每种类型之前,请检查(使用谓词contains
(是否已经在输出元组中。如果没有,则添加了(否则" std::conditional
的分支",否则就不会添加(the'the" the" the' std::conditional
的分支(。
如果您可以访问Boost,则可以使用boost::mp11::mp_unique<your_tuple_type>
直接完成。
例如:
{
using not_unique = std::tuple<int, int, char, std::string, double, int>;
using filtered = boost::mp11::mp_unique<not_unique>;
static_assert(std::is_same_v<std::tuple<int, char, std::string, double>, filtered>);
}
{
using already_unique = std::tuple<int, char, std::string, double>;
using filtered = boost::mp11::mp_unique<already_unique>;
static_assert(std::is_same_v<std::tuple<int, char, std::string, double>, filtered>);
}
实时示例
我发现,关于'constexpr'语句的推理通常更容易,而不是在我的脑海中划分std ::。
为此,我调整了Piotr的答案以适合这种形式:现场演示
template < typename T, typename ...Rest >
constexpr auto make_unique_tuple( std::tuple< T, Rest... > )
{
if constexpr ( ( std::is_same_v< T, Rest > || ... ) )
{
return make_unique_tuple( std::tuple< Rest... >{} );
}
else
{
if constexpr ( sizeof...( Rest ) > 0 )
{
using remaining = decltype( make_unique_tuple( std::tuple< Rest... >{} ) );
return std::tuple_cat( std::tuple< T >{}, remaining{} );
}
else
{
return std::tuple< T >{};
}
}
}
piotr的代码非常简洁,应该优先。这里是一般variadic模板类的扩展版本,可用于C 17(例如std::variant
或自定义容器(:
#include <type_traits>
// end of recursive call: tuple is forwared using `type`
template <typename T, typename... Ts>
struct unique_impl {using type = T;};
// recursive call: 1. Consumes the first type of the variadic arguments,
// if not repeated add it to the tuple.
// 2. Call this again with the rest of arguments
template <template<class...> class Tuple, typename... Ts, typename U, typename... Us>
struct unique_impl<Tuple<Ts...>, U, Us...>
: std::conditional_t<(std::is_same_v<U, Ts> || ...)
, unique_impl<Tuple<Ts...>, Us...>
, unique_impl<Tuple<Ts..., U>, Us...>> {};
// forward definition
template <class Tuple>
struct unique_tuple;
// class specialization so that tuple arguments can be extracted from type
template <template<class...>class Tuple, typename... Ts>
struct unique_tuple<Tuple<Ts...>> : public unique_impl<Tuple<>, Ts...> {};
实时演示
如果您需要C 11,您只需要替换折叠表达式(std::is_same_v<U, Ts> || ...)
即可使用自制disjunction<...>
(请参阅CPPReference可能实现(。
c 11实现,基于piotr skotnicki和Soilros答案:
#include <type_traits> // for std::false_type, std::conditional
namespace meta {
// Port of std::disjunction from C++14
// Based on: https://en.cppreference.com/w/cpp/types/disjunction
template <typename ... Types>
struct disjunction
: std::false_type
{};
template <typename B1>
struct disjunction<B1>
: B1
{};
template <typename B1, typename ... Bn>
struct disjunction<B1, Bn...>
: std::conditional<
bool(B1::value),
B1,
disjunction<Bn...>
>::type
{};
} // namespace meta
namespace meta {
/**
# Example of usage
@code{.cpp}
template <typename ... Types>
using unique_tuple = typename unique<std::tuple<>, Types ...>::type;
unique_tuple<bool, int, float, int, int, float> tuple; // --> std::tuple<bool, int, float>
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template <typename ... Types>
using unique_variant = typename unique<std::variant<>, Types...>::type;
unique_variant<bool, int, float, int, int, float> var; // --> std::variant<bool, int, float>
@endcode
*/
/**
End of recursive call: tuple is forwared using `type`
Note: In C++20 it may be implemented like:
@code{.cpp}
template <typename T, typename ... Types>
struct unique : std::type_identity<T> {};
@endcode
*/
template <typename T, typename ... Types>
struct unique {
using type = T;
};
/**
Recursive call:
1. Consumes the first type of the variadic arguments,
if not repeated add it to the tuple.
2. Call this again with the rest of arguments
Note: In C++17 it may be implemented by using fold-expression:
@code{.cpp}
template <
template<class...> class Tuple, typename... TupleTypes,
typename U, typename... Us
>
struct unique<Tuple<TupleTypes...>, U, Us...>
: std::conditional<
(std::is_same_v<U, TupleTypes> || ...)
, unique_impl<Tuple<TupleTypes...>, Us...>
, unique_impl<Tuple<TupleTypes..., U>, Us...>>::type
{};
@endcode
*/
template <
template<class...> class Tuple, typename... TupleTypes,
typename U, typename... Us
>
struct unique< Tuple<TupleTypes...> , U, Us...>
: std::conditional<
disjunction< std::is_same<U, TupleTypes> ... >::value
, unique<Tuple<TupleTypes...>, Us...>
, unique<Tuple<TupleTypes..., U>, Us...>
>::type
{};
} // namespace meta
编译时间测试/验证:
#include <tuple>
namespace tests {
using namespace meta;
// No-types check
static_assert(std::is_same<
unique< std::tuple<> >::type,
std::tuple<>
>::value == true, "Test failed");
// Single type check
static_assert(std::is_same<
unique< std::tuple<>, bool >::type,
std::tuple<bool>
>::value == true, "Test failed");
// No-duplicates check
static_assert(std::is_same<
unique< std::tuple<>, bool, int, float >::type,
std::tuple<bool, int, float>
>::value == true, "Test failed");
// Single duplicate check
static_assert(std::is_same<
unique< std::tuple<>, int, int>::type,
std::tuple<int>
>::value == true, "Test failed");
// Multiple duplicates check
static_assert(std::is_same<
unique< std::tuple<>, int, int, int, int, int >::type,
std::tuple<int>
>::value == true, "Test failed");
// Few duplicates check
static_assert(std::is_same<
unique< std::tuple<>, int, int, float, float >::type,
std::tuple<int, float>
>::value == true, "Test failed");
// Duplicates in the middle check
static_assert(std::is_same<
unique< std::tuple<>, bool, int, int, int, float, float, float, double >::type,
std::tuple<bool, int, float, double>
>::value == true, "Test failed");
// Duplicates mixed check
static_assert(std::is_same<
unique< std::tuple<>, bool, int, int, int, float, double, double, int, bool, bool>::type,
std::tuple<bool, int, float, double>
>::value == true, "Test failed");
// Duplicates mixed check
static_assert(std::is_same<
unique< std::tuple<>, bool, int, float, bool, int, float >::type,
std::tuple<bool, int, float>
>::value == true, "Test failed");
// Duplicated type-alias check
static_assert(std::is_same<
unique< std::tuple<>, short, int, std::int16_t, std::int32_t >::type,
std::tuple<short, int>
>::value == true, "Test failed");
// Duplicated type-alias check
static_assert(std::is_same<
unique< std::tuple<>, signed char, std::int8_t >::type,
std::tuple<signed char>
>::value == true, "Test failed");
} // namespace tests
[Godbolt]
相关文章:
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 通过C++从目录中过滤特定文件类型
- 如何从元组C 过滤重复类型
- 如何使用元编程过滤常量类型和非常量类型
- 如何根据表达式在Boost.Hana中是否有效来过滤类型元组
- 在c++中过滤类型名
- 使用boost::hana过滤类型列表
- 将std::shared_ptr类型的容器(std::vector)过滤为std::weak_ptr类型的容器