Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions include/boost/variant/variant_alternative.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright (c) 2017
// Mikhail Maximov
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_VARIANT_ALTERNATIVE_HPP
#define BOOST_VARIANT_ALTERNATIVE_HPP

#include <boost/config.hpp>

#include <boost/mpl/at.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/vector.hpp>

#include <boost/type_traits/add_const.hpp>
#include <boost/type_traits/add_cv.hpp>
#include <boost/type_traits/add_volatile.hpp>
#include <boost/type_traits/conditional.hpp>

namespace boost {
namespace detail {
namespace variant {

// copies sequence to mpl::list, then uses mpl::at to get I-th type
template <size_t I, class Sequence>
struct type_in_seqeunce {
private:
typedef typename boost::mpl::insert_range<
boost::mpl::list<>
, boost::mpl::end< boost::mpl::list<> >::type
, typename Sequence::type
>::type sequence;
public:
typedef typename mpl::at<
sequence,
mpl::integral_c<size_t, I> >::type type;
};

#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
// variant_alternative_impl using variadic templates

template <size_t I, class Type, class... Types>
struct get_type {
typedef typename get_type<I - 1, Types...>::type type;
};

template <class Type, class... Types>
struct get_type<0, Type, Types...> {
typedef Type type;
};

template <size_t I, class... Types>
struct variant_alternative_impl {
typedef typename get_type<I, Types...>::type type;
};

// variant_alternative_impl specialization for make_variant_over_sequence
template <size_t I, class Sequence>
struct variant_alternative_impl<I, over_sequence<Sequence> > {
typedef typename type_in_seqeunce<I, Sequence>::type type;
};

#else // defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
// variant_alternative_impl without variadic templates using BOOST_VARIANT_ENUM_PARAMS

template <size_t I, BOOST_VARIANT_ENUM_PARAMS(class Types)>
struct variant_alternative_impl:
mpl::at<
mpl::vector<BOOST_VARIANT_ENUM_PARAMS(Types)>,
mpl::integral_c<size_t, I> > {};

// variant_alternative_impl specialization for make_variant_over_sequence
template <size_t I, class Sequence, BOOST_VARIANT_ENUM_SHIFTED_PARAMS(class T)>
struct variant_alternative_impl<I, detail::variant::over_sequence<Sequence>, BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T)> {
typedef typename type_in_seqeunce<I, Sequence>::type type;
};

#endif

} // namespace variant
} // namespace detail

template <size_t I, class T> struct variant_alternative; // undefined

#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
// variant_alternative using variadic templates

template <size_t I, class... Types>
struct variant_alternative<I, variant<Types...>> {
typedef typename detail::variant::variant_alternative_impl<I, Types...>::type type;
};

#else // defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
// variant_alternative without variadic_templates using BOOST_VARIANT_ENUM_PARAMS

template <size_t I, BOOST_VARIANT_ENUM_PARAMS(class Types)>
struct variant_alternative<I, variant<BOOST_VARIANT_ENUM_PARAMS(Types) > > {
typedef typename detail::variant::variant_alternative_impl<I, BOOST_VARIANT_ENUM_PARAMS(Types)>::type type;
};

#endif

// cv-qualifiers handlers
template <size_t I, class T> struct variant_alternative<I, const T> {
typedef typename add_const<typename variant_alternative<I, T>::type>::type type;
};

template <size_t I, class T> struct variant_alternative<I, volatile T> {
typedef typename add_volatile<typename variant_alternative<I, T>::type>::type type;
};

template <size_t I, class T> struct variant_alternative<I, const volatile T> {
typedef typename add_cv<typename variant_alternative<I, T>::type>::type type;
};

#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
template <size_t I, class T>
using variant_alternative_t = typename variant_alternative<I, T>::type;
#endif

} // namespace boost

#endif // BOOST_VARIANT_ALTERNATIVE_HPP
1 change: 1 addition & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ test-suite variant
[ run overload_selection.cpp ]
[ run recursive_wrapper_move_test.cpp ]
[ run variant_over_joint_view_test.cpp ]
[ run variant_alternative_test.cpp ]
;


97 changes: 97 additions & 0 deletions test/variant_alternative_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2017
// Mikhail Maximov
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <string>

#include "boost/config.hpp"

#include "boost/test/minimal.hpp"
#include "boost/variant.hpp"
#include "boost/variant/variant_alternative.hpp"

#include "boost/type_traits/add_const.hpp"
#include "boost/type_traits/add_cv.hpp"
#include "boost/type_traits/add_volatile.hpp"
#include "boost/type_traits/integral_constant.hpp"
#include "boost/type_traits/is_const.hpp"
#include "boost/type_traits/is_volatile.hpp"
#include "boost/type_traits/remove_cv.hpp"

template<bool B1, bool B2>
struct logical_and: boost::false_type {};

template<>
struct logical_and<true, true>: boost::true_type {};

template<class T>
struct is_cv : logical_and<boost::is_const<T>::value, boost::is_volatile<T>::value> {};

void test_correct_type() {
typedef boost::variant<int, std::string> variant_t;
typedef typename boost::variant_alternative<0, variant_t>::type first_type;
typedef typename boost::variant_alternative<1, variant_t>::type second_type;
variant_t v;
v = 1;
BOOST_CHECK(boost::get<first_type>(v) == 1);
v = "2";
BOOST_CHECK(boost::get<second_type>(v) == "2");
}

void test_correct_alias_type() {
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
typedef boost::variant<int, std::string> variant_t;
typedef typename boost::variant_alternative_t<0, variant_t> first_type;
typedef typename boost::variant_alternative_t<1, variant_t> second_type;
variant_t v;
v = 1;
BOOST_CHECK(boost::get<first_type>(v) == 1);
v = "2";
BOOST_CHECK(boost::get<second_type>(v) == "2");
#endif
}

template<template <typename> class cv_qualifier, template <typename> class cv_check>
void test_correct_cv() {
typedef typename boost::variant<int, std::string> variant_t;
typedef typename cv_qualifier<variant_t>::type cv_variant_t;
typedef typename boost::variant_alternative<0, cv_variant_t>::type cv_first_type;
typedef typename boost::variant_alternative<1, cv_variant_t>::type cv_second_type;
typedef typename boost::remove_cv<cv_first_type>::type first_type;
typedef typename boost::remove_cv<cv_second_type>::type second_type;

BOOST_CHECK(cv_check<cv_first_type>::value);
BOOST_CHECK(cv_check<cv_second_type>::value);

variant_t v;
v = 1;
BOOST_CHECK(boost::get<first_type>(v) == 1);
v = "2";
BOOST_CHECK(boost::get<second_type>(v) == "2");
}

void test_over_sequence_type() {
typedef boost::variant<int> v1;
typedef boost::variant<std::string> v2;
typedef boost::make_variant_over<boost::mpl::joint_view<v1::types, v2::types>::type>::type variant_t;
typedef typename boost::variant_alternative<0, variant_t>::type first_type;
typedef typename boost::variant_alternative<1, variant_t>::type second_type;
variant_t v;
v = 1;
BOOST_CHECK(boost::get<first_type>(v) == 1);
v = "2";
BOOST_CHECK(boost::get<second_type>(v) == "2");
}

int test_main(int , char* []) {
test_correct_type();
test_correct_cv<boost::add_const, boost::is_const>();
test_correct_cv<boost::add_volatile, boost::is_volatile>();
test_correct_cv<boost::add_cv, is_cv>();
test_over_sequence_type();
test_correct_alias_type();
return 0;
}