주어진 std :: variant 유형을 주어진 기준으로 나눕니다.


20

지정된 변형 유형별 방법

using V = std::variant<bool, char, std::string, int, float, double, std::vector<int>>;

두 가지 변형 유형을 선언하십시오.

using V1 = std::variant<bool, char, int, float, double>;
using V2 = std::variant<std::string, std::vector<int>>;

여기서 V1모든 연산 종류를 포함 V하고 V2있는 모든 종류의 비 산술 포함 V?

V 템플리트 클래스의 매개 변수 일 수 있습니다 (예 :

template <class V>
struct TheAnswer
{
    using V1 = ?;
    using V2 = ?;
};

일반적으로 기준은 다음 constexpr과 같은 변수 가 될 수 있습니다 .

template <class T>
constexpr bool filter;

답변:


6

당신이 배리의 짧은 합리적인 해답을 사용하지 않을 어떤 이유, 여기에 (감사 @ 둘 다없는 한 경우 xskxzr 어색한 "부트 스트랩"전문성을 제거하고 @에 max66 빈 변형 코너 케이스에 대해 나에게 경고하기위한) :

namespace detail {
    template <class V>
    struct convert_empty_variant {
        using type = V;
    };

    template <>
    struct convert_empty_variant<std::variant<>> {
        using type = std::variant<std::monostate>;
    };

    template <class V>
    using convert_empty_variant_t = typename convert_empty_variant<V>::type;

    template <class V1, class V2, template <class> class Predicate, class V>
    struct split_variant;

    template <class V1, class V2, template <class> class Predicate>
    struct split_variant<V1, V2, Predicate, std::variant<>> {
        using matching = convert_empty_variant_t<V1>;
        using non_matching = convert_empty_variant_t<V2>;
    };

    template <class... V1s, class... V2s, template <class> class Predicate, class Head, class... Tail>
    struct split_variant<std::variant<V1s...>, std::variant<V2s...>, Predicate, std::variant<Head, Tail...>>
    : std::conditional_t<
        Predicate<Head>::value,
        split_variant<std::variant<V1s..., Head>, std::variant<V2s...>, Predicate, std::variant<Tail...>>,
        split_variant<std::variant<V1s...>, std::variant<V2s..., Head>, Predicate, std::variant<Tail...>>
    > { };
}

template <class V, template <class> class Predicate>
using split_variant = detail::split_variant<std::variant<>, std::variant<>, Predicate, V>;

완드 박스에서 라이브로보기


아마도 당신은 이런 식으로Types... 내부를 std::variant직접 풀 수 있을까요?
xskxzr

죄송 합니다만 .. 내가 아는 한 공란 std::variant이 잘못되었습니다.
max66

@ max66 분명히 인스턴스화 만 잘못되어 있으므로 분명히 std::variant<>알 수 있습니다. 나는 그래서 그것을 조정할 것 V1하고 V2다시 가을 std::variant<std::monostate>하지만.
Quentin

아 ... 인스턴스화 한 경우에만 잘못된 형식 ... 확인; 나에게 합리적인 것 같습니다.
max66

14

Boost.Mp11을 사용하면 이것은 항상 하나의 짧은 라이너입니다.

using V1 = mp_filter<std::is_arithmetic, V>;
using V2 = mp_remove_if<V, std::is_arithmetic>;

다음을 사용할 수도 있습니다.

using V1 = mp_copy_if<V, std::is_arithmetic>;

두 가지를 더 대칭 적으로 만듭니다.


또는

using P = mp_partition<V, std::is_arithmetic>;
using V1 = mp_first<P>;
using V2 = mp_second<P>;

이것은 어떤 아이디어를 mp_filter기반으로합니까?
Alexey Starinsky

@AlexeyStarinsky 질문을 이해하지 못합니다-무슨 뜻입니까, 어떤 아이디어?
Barry

3
@AlexeyStarinsky 문서를 읽고, Peter가 작성한 일부 게시물에 대한 링크도 제공합니다.
배리

4
@MaximEgorushkin 최고의 메타 프로그래밍 라이브러리 imo입니다. 내가 시작 여기에 대한 답변을 많이 가지고 "Boost.Mp11, 이것은 짧은 한 줄입니다"
배리

1
@ Barry 지금 문서를 읽고 있는데 boost.MPL보다 훨씬 좋습니다.
Maxim Egorushkin

2

편집 빈 변종 (감안할 때 std::variant<>) 병 (따라 형성된다 cppreference을 )하고 사용해야 std::variant<std::monostate>대신에, 나는 (A 추가 답변을 수정 한 tuple2variant()경우를 지원하기 위해 빈 튜플에 대한 전문성을) 때의 유형 목록 V1또는 V2비어 있습니다.


조금 decltype()섬망이지만 ... 도우미 필터 함수를 다음과 같이 선언하면

template <bool B, typename T>
constexpr std::enable_if_t<B == std::is_arithmetic_v<T>, std::tuple<T>>
   filterArithm ();

template <bool B, typename T>
constexpr std::enable_if_t<B != std::is_arithmetic_v<T>, std::tuple<>>
   filterArithm ();

및 변형 함수 튜플 (빈 튜플 전문화와는 빈을 피하기 위해 std::variant)

std::variant<std::monostate> tuple2variant (std::tuple<> const &);

template <typename ... Ts>
std::variant<Ts...> tuple2variant (std::tuple<Ts...> const &);

당신의 수업은 단순히 (?)

template <typename ... Ts>
struct TheAnswer<std::variant<Ts...>>
 {
   using V1 = decltype(tuple2variant(std::declval<
                 decltype(std::tuple_cat( filterArithm<true, Ts>()... ))>()));
   using V2 = decltype(tuple2variant(std::declval<
                 decltype(std::tuple_cat( filterArithm<false, Ts>()... ))>()));
 };

좀 더 일반적인 것을 원한다면 ( std::arithmetic템플릿 매개 변수 로 전달하려는 경우 ) filterArithm()템플릿 템플릿 필터 매개 변수를 전달하는 함수를 수정할 수 있습니다 F( filterType())

template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B == F<T>::value, std::tuple<T>>
   filterType ();

template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B != F<T>::value, std::tuple<>>
   filterType ();

TheAnswer클래스가 될

template <typename, template <typename> class>
struct TheAnswer;

template <typename ... Ts, template <typename> class F>
struct TheAnswer<std::variant<Ts...>, F>
 {
   using V1 = decltype(tuple2variant(std::declval<decltype(
                 std::tuple_cat( filterType<F, true, Ts>()... ))>()));
   using V2 = decltype(tuple2variant(std::declval<decltype(
                 std::tuple_cat( filterType<F, false, Ts>()... ))>()));
 };

그리고 TA선언도std::is_arithmetic

using TA = TheAnswer<std::variant<bool, char, std::string, int, float,
                                  double, std::vector<int>>,
                     std::is_arithmetic>;

다음은 std::is_arithmetic매개 변수로 V2빈 대소 문자 를 사용한 전체 컴파일 예입니다.

#include <tuple>
#include <string>
#include <vector>
#include <variant>
#include <type_traits>

std::variant<std::monostate> tuple2variant (std::tuple<> const &);

template <typename ... Ts>
std::variant<Ts...> tuple2variant (std::tuple<Ts...> const &);

template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B == F<T>::value, std::tuple<T>>
   filterType ();

template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B != F<T>::value, std::tuple<>>
   filterType ();

template <typename, template <typename> class>
struct TheAnswer;

template <typename ... Ts, template <typename> class F>
struct TheAnswer<std::variant<Ts...>, F>
 {
   using V1 = decltype(tuple2variant(std::declval<decltype(
                 std::tuple_cat( filterType<F, true, Ts>()... ))>()));
   using V2 = decltype(tuple2variant(std::declval<decltype(
                 std::tuple_cat( filterType<F, false, Ts>()... ))>()));
 };

int main ()
 {
   using TA = TheAnswer<std::variant<bool, char, std::string, int, float,
                                     double, std::vector<int>>,
                        std::is_arithmetic>;
   using TB = TheAnswer<std::variant<bool, char, int, float, double>,
                        std::is_arithmetic>;

   using VA1 = std::variant<bool, char, int, float, double>;
   using VA2 = std::variant<std::string, std::vector<int>>;
   using VB1 = VA1;
   using VB2 = std::variant<std::monostate>;

   static_assert( std::is_same_v<VA1, TA::V1> );
   static_assert( std::is_same_v<VA2, TA::V2> );
   static_assert( std::is_same_v<VB1, TB::V1> );
   static_assert( std::is_same_v<VB2, TB::V2> );
 }

귀하의 솔루션이 작동하지 않습니다 void.
xskxzr

@xskxzr-죄송 합니다만 귀하의 반대 의견을 이해하지 못합니다. void내가 아는 한에서 유형으로 금지되어 std::variant있습니다.
max66

1
내 나쁜, 나는 잘 std::variant<void>형성 되지 않았다는 것을 std::variant<>알았지 만 그 정의가 인스턴스화되지 않으면 괜찮습니다 .
xskxzr
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.