Commit abf66536 authored by Dominik Charousset's avatar Dominik Charousset

Make variant more C++17 compliant, close #525

parent 42309315
......@@ -204,7 +204,7 @@ public:
T
>::type
>::type;
if (get<cfg_type>(&x) && assign_config_value(ref_, get<cfg_type>(x)))
if (get_if<cfg_type>(&x) && assign_config_value(ref_, get<cfg_type>(x)))
return;
type_name_visitor tnv;
report_type_error(ln, x, tnv(ref_), errors);
......@@ -262,7 +262,7 @@ public:
>::type
>::type;
value_type tmp;
if (get<cfg_type>(&x) && assign_config_value(tmp, get<cfg_type>(x))) {
if (get_if<cfg_type>(&x) && assign_config_value(tmp, get<cfg_type>(x))) {
ref_.insert(ref_.end(), std::move(tmp));
return;
}
......
......@@ -168,7 +168,7 @@ protected:
}
} else {
if (derived.current_stream_state_ != derived.streams_.end()) {
apply_visitor(derived, x.content);
visit(derived, x.content);
} else {
CAF_LOG_ERROR("Unable to access required stream and/or path state.");
derived.fail(sec::invalid_stream_state);
......
......@@ -47,6 +47,8 @@
namespace caf {
constexpr size_t variant_npos = static_cast<size_t>(-1);
template <class T>
struct variant_assign_helper {
using result_type = void;
......@@ -102,11 +104,15 @@ public:
static constexpr int max_type_id = sizeof...(Ts) - 1;
static_assert(sizeof...(Ts) <= 20, "Too many template arguments");
static_assert(sizeof...(Ts) <= 20, "Too many template arguments given.");
static_assert(sizeof...(Ts) > 0, "No template argument given.");
static_assert(!detail::tl_exists<types, std::is_reference>::value,
"Cannot create a variant of references");
using type0 = typename detail::tl_at<types, 0>::type;
variant& operator=(const variant& other) {
variant_assign_helper<variant> helper{*this};
other.apply(helper);
......@@ -119,13 +125,15 @@ public:
return *this;
}
variant() : type_(0) {
// never empty
variant() : type_(variant_npos) {
// Never empty ...
set(typename detail::tl_head<types>::type());
// ... unless an exception was thrown above.
type_ = 0;
}
template <class U>
variant(U&& arg) : type_(-1) {
variant(U&& arg) : type_(variant_npos) {
set(std::forward<U>(arg));
}
......@@ -135,12 +143,12 @@ public:
return *this;
}
variant(const variant& other) : type_(-1) {
variant(const variant& other) : type_(variant_npos) {
variant_assign_helper<variant> helper{*this};
other.apply(helper);
}
variant(variant&& other) : type_(-1) {
variant(variant&& other) : type_(variant_npos) {
variant_move_helper<variant> helper{*this};
other.apply(helper);
}
......@@ -149,6 +157,14 @@ public:
destroy_data();
}
constexpr size_t index() const {
return static_cast<size_t>(type_);
}
bool valueless_by_exception() const {
return index() == variant_npos;
}
/// @cond PRIVATE
template <int Pos>
bool is(std::integral_constant<int, Pos>) const {
......@@ -177,22 +193,20 @@ public:
}
template <class Visitor>
typename Visitor::result_type apply(Visitor& visitor) const {
return apply_impl(*this, visitor);
auto apply(Visitor&& visitor) const
-> decltype(visitor(std::declval<const type0&>())) {
return apply_impl(*this, std::forward<Visitor>(visitor));
}
template <class Visitor>
typename Visitor::result_type apply(Visitor& visitor) {
return apply_impl(*this, visitor);
}
int8_t type_tag() {
return static_cast<int8_t>(type_);
auto apply(Visitor&& visitor) -> decltype(visitor(std::declval<type0&>())) {
return apply_impl(*this, std::forward<Visitor>(visitor));
}
template <class Self, class Visitor>
static typename Visitor::result_type
apply_impl(Self& x, Visitor& f) {
static auto apply_impl(Self& x, Visitor&& f) -> decltype(
f(std::declval<typename std::conditional<std::is_const<Self>::value,
const type0, type0>::type&>())) {
switch (x.type_) {
default: CAF_RAISE_ERROR("invalid type found");
CAF_VARIANT_CASE(0);
......@@ -221,7 +235,7 @@ public:
private:
inline void destroy_data() {
if (type_ == -1) return; // nothing to do
if (type_ == variant_npos) return; // nothing to do
detail::variant_data_destructor f;
apply(f);
}
......@@ -273,10 +287,16 @@ private:
other.apply(helper);
}
int type_;
size_t type_;
detail::variant_data<typename lift_void<Ts>::type...> data_;
};
template <class T>
struct is_variant : std::false_type {};
template <class... Ts>
struct is_variant<variant<Ts...>> : std::true_type {};
/// @relates variant
template <class T, class... Us>
T& get(variant<Us...>& value) {
......@@ -297,7 +317,7 @@ const T& get(const variant<Us...>& value) {
/// @relates variant
template <class T, class... Us>
T* get(variant<Us...>* value) {
T* get_if(variant<Us...>* value) {
using namespace detail;
int_token<tl_index_where<type_list<Us...>,
tbind<is_same_ish, T>::template type>::value> token;
......@@ -308,22 +328,33 @@ T* get(variant<Us...>* value) {
/// @relates variant
template <class T, class... Us>
const T* get(const variant<Us...>* value) {
const T* get_if(const variant<Us...>* value) {
// compiler implicitly restores const because of the return type
return get<T>(const_cast<variant<Us...>*>(value));
return get_if<T>(const_cast<variant<Us...>*>(value));
}
/// @relates variant
template <class Visitor, class... Ts>
typename Visitor::result_type
apply_visitor(Visitor& visitor, const variant<Ts...>& data) {
CAF_DEPRECATED apply_visitor(Visitor& visitor, const variant<Ts...>& data) {
return data.apply(visitor);
}
/// @relates variant
template <class Visitor, class Variant,
class E =
typename std::enable_if<
is_variant<typename std::decay<Variant>::type>::value
>::type>
auto visit(Visitor&& visitor, Variant&& data)
-> decltype(data.apply(std::forward<Visitor>(visitor))) {
return data.apply(visitor);
}
/// @relates variant
template <class Visitor, class... Ts>
typename Visitor::result_type
apply_visitor(Visitor& visitor, variant<Ts...>& data) {
CAF_DEPRECATED apply_visitor(Visitor& visitor, variant<Ts...>& data) {
return data.apply(visitor);
}
......@@ -342,7 +373,7 @@ struct variant_compare_helper {
}
template <class U>
bool operator()(const U& rhs) const {
auto ptr = get<U>(&lhs);
auto ptr = get_if<U>(&lhs);
return ptr ? *ptr == rhs : false;
}
};
......@@ -351,7 +382,7 @@ struct variant_compare_helper {
template <class... Ts>
bool operator==(const variant<Ts...>& x, const variant<Ts...>& y) {
variant_compare_helper<variant<Ts...>> f{x};
return apply_visitor(f, y);
return visit(f, y);
}
/// @relates variant
......@@ -370,7 +401,7 @@ bool operator==(const variant<Ts...>& x, const T& y) {
/// @relates variant
template <class T>
struct variant_reader {
int8_t& type_tag;
size_t& type_tag;
T& x;
};
......@@ -378,7 +409,8 @@ struct variant_reader {
template <class Inspector, class... Ts>
typename Inspector::result_type
inspect(Inspector& f, variant_reader<variant<Ts...>>& x) {
return variant<Ts...>::apply_impl(x.x, f);
return x.x.apply(f);
//return variant<Ts...>::apply_impl(x.x, f);
}
/// @relates variant
......@@ -386,7 +418,7 @@ template <class Inspector, class... Ts>
typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type
inspect(Inspector& f, variant<Ts...>& x) {
auto type_tag = x.type_tag();
auto type_tag = x.index();
variant_reader<variant<Ts...>> helper{type_tag, x};
return f(meta::omittable(), type_tag, helper);
}
......@@ -394,7 +426,7 @@ inspect(Inspector& f, variant<Ts...>& x) {
/// @relates variant
template <class T>
struct variant_writer {
int8_t& type_tag;
size_t& type_tag;
T& x;
};
......@@ -432,7 +464,7 @@ template <class Inspector, class... Ts>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
inspect(Inspector& f, variant<Ts...>& x) {
int8_t type_tag;
size_t type_tag;
variant_writer<variant<Ts...>> helper{type_tag, x};
return f(meta::omittable(), type_tag, helper);
}
......
......@@ -79,7 +79,7 @@ void config_option::report_type_error(size_t ln, config_value& x,
type_name_visitor tnv;
*out << "error in line " << ln << ": expected "
<< expected << " found "
<< apply_visitor(tnv, x) << '\n';
<< visit(tnv, x) << '\n';
}
} // namespace caf
......@@ -654,7 +654,7 @@ bool scheduled_actor::handle_stream_msg(mailbox_element& x,
auto& sm = x.content().get_mutable_as<stream_msg>(0);
auto e = streams_.end();
stream_msg_visitor f{this, sm.sid, streams_.find(sm.sid), e, active_behavior};
auto res = apply_visitor(f, sm.content);
auto res = visit(f, sm.content);
auto success = (res.first == none);
auto i = res.second;
if (!success) {
......
......@@ -129,7 +129,7 @@ struct fixture {
optional<std::ostream&>) {
message_visitor mv;
anon_send(config_server, put_atom::value,
std::move(key), apply_visitor(mv, value));
std::move(key), visit(mv, value));
};
load_impl(consume, str);
}
......@@ -189,7 +189,7 @@ struct fixture {
T
>::type
>::type;
auto ptr = get<type>(&cv);
auto ptr = get_if<type>(&cv);
return ptr != nullptr && detail::safe_equal(*ptr, what);
}
......
......@@ -68,7 +68,7 @@ ostream& operator<<(ostream& out, const maybe<T>& x) {
using std::to_string;
using caf::to_string;
using caf::io::basp::to_string;
if (get<anything>(&x) != nullptr)
if (caf::get_if<anything>(&x) != nullptr)
return out << "*";
return out << to_string(get<T>(x));
}
......@@ -79,7 +79,7 @@ namespace caf {
template <class T, class U>
bool operator==(const maybe<T>& x, const U& y) {
return get<anything>(&x) != nullptr || get<T>(x) == y;
return get_if<anything>(&x) != nullptr || get<T>(x) == y;
}
template <class T, class U>
......@@ -89,7 +89,7 @@ bool operator==(const T& x, const maybe<U>& y) {
template <class T>
std::string to_string(const maybe<T>& x) {
return !get<anything>(&x) ? std::string{"*"} : deep_to_string(get<T>(x));
return !get_if<anything>(&x) ? std::string{"*"} : deep_to_string(get<T>(x));
}
} // namespace caf
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment