Commit 4badfac1 authored by Jason Rhinelander's avatar Jason Rhinelander

C++14 simplifications

Replace `typename std::enable_if<...>::type` with
`std::enable_if_t<...>`
Replace various `typename = enable_if_t<...>` with `enable_if_t<..., int> = 0`
which allows for better overloading.
parent 4aa57a90
......@@ -298,11 +298,7 @@ class BundleSigned {
/// transferApprox() is a deprecated name for transfer()
template <typename... Args>
#if __cplusplus >= 201402L
[[deprecated("transferApprox() is deprecated; use transfer() instead")]]
#else
[[deprecated]]
#endif
BundleSigned transferApprox(Args &&...args) {
return transfer(std::forward<Args>(args)...);
}
......
......@@ -269,9 +269,9 @@ class Member : private noncopyable {
void add(const SharedMember<Member> &member);
/** Container-accepting version of add(). */
template <class Container>
typename std::enable_if<std::is_base_of<Member, typename Container::value_type::member_type>::value
>::type add(const Container &members) {
template <class Container,
std::enable_if_t<std::is_base_of<Member, typename Container::value_type::member_type>::value, int> = 0>
void add(const Container &members) {
bool add_failed = false;
for (auto &mem : members) {
if (!try_add(mem)) { // Adding the member would block
......@@ -362,13 +362,14 @@ class Member : private noncopyable {
* You must ensure that the returned object does not persist beyond the lifetime of
* the lock it is based upon.
*/
[[gnu::warn_unused_result]] Supplemental supplement(const SharedMember<Member> &member);
[[gnu::warn_unused_result]]
Supplemental supplement(const SharedMember<Member> &member);
/** Container-accepting version of supplement() */
template <class Container>
template <class Container,
std::enable_if_t<std::is_base_of<Member, typename Container::value_type::member_type>::value, int> = 0>
[[gnu::warn_unused_result]]
typename std::enable_if<std::is_base_of<Member, typename Container::value_type::member_type>::value, Supplemental
>::type supplement(const Container &members) {
Supplemental supplement(const Container &members) {
return Supplemental(*this, members);
}
......@@ -387,9 +388,9 @@ class Member : private noncopyable {
* \throws std::out_of_range if the lock doesn't contain one or more of the given
* members.
*/
template <class Container>
typename std::enable_if<std::is_base_of<Member, typename Container::value_type::member_type>::value, Lock
>::type remove(const Container &members) {
template <class Container,
std::enable_if_t<std::is_base_of<Member, typename Container::value_type::member_type>::value, int> = 0>
Lock remove(const Container &members) {
if (members.empty()) return Lock(isWrite(), isLocked()); // Fake lock
std::multiset<SharedMember<Member>> new_lock_members;
......@@ -526,11 +527,10 @@ class Member : private noncopyable {
*
* \sa Member::Lock
*/
template <class Container>
[[gnu::warn_unused_result]] Lock writeLock(const Container &plus,
typename std::enable_if<
std::is_base_of<Member, typename Container::value_type::member_type>::value
>::type* = 0) const {
template <class Container,
std::enable_if_t<std::is_base_of<Member, typename Container::value_type::member_type>::value, int> = 0>
[[gnu::warn_unused_result]]
Lock writeLock(const Container &plus) const {
return rwLock_(true, plus);
}
......@@ -656,11 +656,9 @@ class Member : private noncopyable {
void unlock_many_(bool write, const std::multiset<SharedMember<Member>> &plus);
/// Helper class doing all the grunt work of the Container version of readLock/writeLock.
template <class Container>
Lock rwLock_(const bool &write, const Container &plus,
typename std::enable_if<
std::is_base_of<Member, typename Container::value_type::member_type>::value
>::type* = 0) const {
template <class Container,
std::enable_if_t<std::is_base_of<Member, typename Container::value_type::member_type>::value, int> = 0>
Lock rwLock_(const bool &write, const Container &plus) const {
const bool has_sim = hasSimulation();
if (has_sim and maxThreads() == 0) return Member::Lock(write); // Fake lock
std::multiset<SharedMember<Member>> members;
......
......@@ -2,6 +2,7 @@
#include <stdexcept>
#include <vector>
#include <ostream>
#include <eris/types.hpp>
namespace eris {
......@@ -24,8 +25,11 @@ class Position final {
* Position({3.0, -4.1}) // initializer list
* Position(v) // v is vector<double> (or any sort of iterable container)
*/
template <class Container, typename = typename std::enable_if<std::is_arithmetic<typename Container::value_type>::value>::type>
Position(const Container &coordinates);
template <class Container, std::enable_if_t<std::is_arithmetic<typename Container::value_type>::value, int> = 0>
Position(const Container &coordinates) : pos_(coordinates.begin(), coordinates.end()) {
if (dimensions == 0)
throw std::out_of_range("Cannot initialize a Position with 0 dimensions");
}
/** Creates a Position at the given vector, making a copy of the vector.
*
......@@ -107,18 +111,30 @@ class Position final {
* \throws std::out_of_range exception if any of the given dimension indices are invalid, or
* if the dimension list is empty.
*/
template <class Container>
typename std::enable_if<std::is_integral<typename Container::value_type>::value, Position>::type
subdimensions(const Container &dimensions) const;
template <class Container, std::enable_if_t<std::is_integral<typename Container::value_type>::value, int> = 0>
Position subdimensions(const Container &dims) const {
std::vector<double> p;
p.reserve(dims.size());
for (auto &d : dims) {
if (d < 0 || d >= dimensions)
throw std::out_of_range("Invalid subdimensions call: attempt to use invalid dimension");
p.push_back(pos_[d]);
}
return Position(std::move(p));
}
/** Accesses the Position's `d`th coordinate, where `d=0` is the first dimension, etc.
*
* \throws std::out_of_range exception for `d >= dimensions`.
*/
double& operator[](size_t d);
double &operator[](size_t d) {
if (d >= dimensions)
throw std::out_of_range("Invalid Position index " + std::to_string(d) + " >= " + std::to_string(dimensions));
return pos_[d];
}
/// Const access to Position coordinates.
const double& operator[](size_t d) const;
const double &operator[](size_t d) const { return const_cast<Position &>(*this)[d]; }
///@{
/// Returns an iterator to the beginning of the position values
......@@ -214,10 +230,15 @@ class Position final {
std::vector<double> pos_;
/// Throws an exception if the current object and `other` have different dimensions.
void requireSameDimensions(const Position &other, const std::string &method) const;
void requireSameDimensions(const Position &other, const std::string &method) const {
requireSameDimensions(other.dimensions, method);
}
/// Throws an exception if the current object doesn't match the given number of dimensions.
void requireSameDimensions(size_t dimensions, const std::string &method) const;
void requireSameDimensions(size_t dims, const std::string &method) const {
if (dimensions != dims)
throw std::length_error(method + "() called with objects of differing dimensions");
}
public:
/** Accesses the number of dimensions of this Position object. This will always be at least
......@@ -227,33 +248,4 @@ class Position final {
const size_t dimensions = pos_.size();
};
template <class Container, typename>
Position::Position(const Container &coordinates) : pos_(coordinates.begin(), coordinates.end()) {
if (not dimensions)
throw std::out_of_range("Cannot initialize a Position with 0 dimensions");
}
inline void Position::requireSameDimensions(size_t dim, const std::string &method) const {
if (dimensions != dim)
throw std::length_error(method + "() called with objects of differing dimensions");
}
inline void Position::requireSameDimensions(const Position &other, const std::string &method) const {
requireSameDimensions(other.dimensions, method);
}
inline double& Position::operator[](size_t d) { if (d >= dimensions) throw std::out_of_range("Invalid Position index " + std::to_string(d) + " >= " + std::to_string(dimensions)); return pos_[d]; }
inline const double& Position::operator[](size_t d) const { if (d >= dimensions) throw std::out_of_range("Invalid Position index " + std::to_string(d) + " >= " + std::to_string(dimensions)); return pos_[d]; }
template <class Container>
typename std::enable_if<std::is_integral<typename Container::value_type>::value, Position>::type
Position::subdimensions(const Container &dims) const {
std::vector<double> p;
p.reserve(dims.size());
for (auto &d : dims) {
if (d < 0 or d >= dimensions) throw std::out_of_range("Invalid subdimensions call: attempt to use invalid dimension");
p.push_back(pos_[d]);
}
return Position(std::move(p));
}
}
......@@ -185,7 +185,7 @@ class Positional : public PositionalBase, public T {
* \throws std::length_error if `p`, `boundary1`, and `boundary2` are not of the same
* dimension.
*/
template <typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
template <typename... Args, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
Positional(const Position &p, const Position &boundary1, const Position &boundary2, Args&&... T_args)
: PositionalBase(p, boundary1, boundary2),
T(std::forward<Args>(T_args)...)
......@@ -197,10 +197,9 @@ class Positional : public PositionalBase, public T {
* Any extra arguments are forwarded to T's constructor.
*/
template<typename... Args, typename Numeric1, typename Numeric2,
typename = typename std::enable_if<
std::is_arithmetic<Numeric1>::value and std::is_arithmetic<Numeric2>::value and
std::is_constructible<T, Args...>::value
>::type>
std::enable_if_t<
std::is_arithmetic<Numeric1>::value && std::is_arithmetic<Numeric2>::value &&
std::is_constructible<T, Args...>::value, int> = 0>
Positional(const Position &p, Numeric1 b1, Numeric2 b2, Args&&... T_args)
: PositionalBase(p, (double) b1, (double) b2),
T(std::forward<Args>(T_args)...)
......@@ -210,7 +209,7 @@ class Positional : public PositionalBase, public T {
*
* Any extra arguments are forwarded to T's constructor.
*/
template <typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
template <typename... Args, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
explicit Positional(const Position &p, Args&&... T_args)
: PositionalBase(p), T(std::forward<Args>(T_args)...)
{}
......
......@@ -106,9 +106,8 @@ class SharedMember final {
* This template specification only participates when upcasting from a derived to a base
* class.
*/
template<class F>
SharedMember(const SharedMember<F> &from,
typename std::enable_if<std::is_base_of<T, F>::value && !std::is_same<T, F>::value>::type* = 0)
template<class F, std::enable_if_t<std::is_base_of<T, F>::value && !std::is_same<T, F>::value, int> = 0>
SharedMember(const SharedMember<F> &from)
: ptr_{std::static_pointer_cast<T,F>(from.ptr())}
{}
......@@ -122,9 +121,8 @@ class SharedMember final {
*
* \throws std::bad_cast if `*from` is not an instance of `T`.
*/
template<class F>
SharedMember(const SharedMember<F> &from,
typename std::enable_if<std::is_base_of<F, T>::value && !std::is_same<T, F>::value>::type* = 0)
template<class F, std::enable_if_t<std::is_base_of<F, T>::value && !std::is_same<T, F>::value, int> = 0>
SharedMember(const SharedMember<F> &from)
: ptr_{std::dynamic_pointer_cast<T,F>(from.ptr())} {
// Raise an exception if the ptr above gave back a null shared pointer: that means the
// cast attempted to cast to a derived class, when the actual object is only a base
......
......@@ -51,8 +51,9 @@ class Simulation : public std::enable_shared_from_this<Simulation>, private nonc
* If subclassing Simulation, you may pass the subclass as a template parameter and any
* needed constructor arguments; they will be forwarded to the subclass constructor.
*/
template <typename T = Simulation, typename... Args, typename = typename std::enable_if<std::is_base_of<Simulation, T>::value>::type>
template <typename T = Simulation, typename... Args>
static std::shared_ptr<T> create(Args &&... args) {
static_assert(std::is_base_of<Simulation, T>::value, "Simulation::create<T>(...) requires T to be eris::Simulation or a subclass");
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
}
......@@ -60,8 +61,9 @@ class Simulation : public std::enable_shared_from_this<Simulation>, private nonc
* std::static_pointer_cast. This should only be called when the simulation instance is
* known to be a subclass of the given type.
*/
template <typename T, typename = typename std::enable_if<std::is_base_of<Simulation, T>::value>::type>
template <typename T>
std::shared_ptr<T> as() {
static_assert(std::is_base_of<Simulation, T>::value, "sim.as<T>(...) requires T to be eris::Simulation or a subclass");
return std::static_pointer_cast<T>(shared_from_this());
}
......@@ -149,8 +151,8 @@ class Simulation : public std::enable_shared_from_this<Simulation>, private nonc
* auto market = sim->spawn<Bertrand>(Bundle(good, 1), Bundle(money, 1));
*/
template <class T, typename... Args>
typename std::enable_if<std::is_base_of<Member, T>::value, SharedMember<T>>::type
spawn(Args&&... args) {
SharedMember<T> spawn(Args&&... args) {
static_assert(std::is_base_of<Member, T>::value, "sim.spawn<T>(...) requires T to be eris::Member or a subclass");
auto member_ptr = std::make_shared<T>(std::forward<Args>(args)...);
return SharedMember<T>(add(member_ptr));
}
......@@ -513,11 +515,9 @@ class Simulation : public std::enable_shared_from_this<Simulation>, private nonc
// Good, or Market classes, or Member, which invalidates the "other" filter cache.
template <class B>
typename std::enable_if<
std::is_same<B, Member>::value or std::is_same<B, Agent>::value or std::is_same<B, Good>::value or std::is_same<B, Market>::value,
void
>::type
invalidateCache() {
void invalidateCache() {
static_assert(std::is_same<B, Member>::value || std::is_same<B, Agent>::value || std::is_same<B, Good>::value || std::is_same<B, Market>::value,
"Internal error: invalidateCache() called with invalid cache type");
std::lock_guard<std::recursive_mutex> lock(member_mutex_);
filter_cache_.erase(std::type_index(typeid(B)));
}
......
......@@ -50,7 +50,7 @@ class WrappedPositionalBase : public PositionalBase {
* \throws std::length_error if p, boundary1, and boundary2 are not of the same dimension.
* \throws std::out_of_range if any element of `dimensions` is not a valid dimension number.
*/
template <class Container, typename = typename std::enable_if<std::is_integral<typename Container::value_type>::value>::type>
template <class Container, std::enable_if_t<std::is_integral<typename Container::value_type>::value, int> = 0>
WrappedPositionalBase(const Position &p, const Position &boundary1, const Position &boundary2, const Container &dimensions)
: PositionalBase(p, boundary1, boundary2)
{
......@@ -99,9 +99,8 @@ class WrappedPositionalBase : public PositionalBase {
*
* \throws std::out_of_range if `dim` is any of the given dimensions is invalid.
*/
template <class Container>
typename std::enable_if<std::is_integral<typename Container::value_type>::value>::type
wrap(const Container &dimensions) {
template <class Container, std::enable_if_t<std::is_integral<typename Container::value_type>::value, int> = 0>
void wrap(const Container &dimensions) {
for (auto &dim : dimensions) {
// The below ("<= and !=") is needed to avoid a warning for "dim < 0" when dim
// is an unsigned type
......@@ -257,7 +256,7 @@ class WrappedPositional : public WrappedPositionalBase, public T {
*
* \param T_args any extra arguments are forwarded to the constructor of class `T`
*/
template<typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
template<typename... Args, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
WrappedPositional(const Position &p, const Position &boundary1, const Position &boundary2,
Args&&... T_args)
: WrappedPositionalBase(p, boundary1, boundary2), T(std::forward<Args>(T_args)...)
......@@ -278,10 +277,10 @@ class WrappedPositional : public WrappedPositionalBase, public T {
* \param T_args any extra arguments are forwarded to the constructor of class `T`
*/
template<typename... Args, typename Numeric1, typename Numeric2,
typename = typename std::enable_if<
std::is_arithmetic<Numeric1>::value and std::is_arithmetic<Numeric2>::value and
std::is_constructible<T, Args...>::value
>::type>
std::enable_if_t<
std::is_arithmetic<Numeric1>::value && std::is_arithmetic<Numeric2>::value &&
std::is_constructible<T, Args...>::value,
int> = 0>
WrappedPositional(const Position &p, Numeric1 b1, Numeric2 b2, Args&&... T_args)
: WrappedPositionalBase(p, (double) b1, (double) b2), T(std::forward<Args>(T_args)...)
{}
......@@ -306,11 +305,10 @@ class WrappedPositional : public WrappedPositionalBase, public T {
* \throws std::length_error if `p`, `boundary1`, and `boundary2` are not of the same dimension.
* \throws std::out_of_range if any element of `dimensions` is not a valid dimension index.
*/
template <class Container, typename... Args,
typename = typename std::enable_if<
std::is_integral<typename Container::value_type>::value and
std::is_constructible<T, Args...>::value
>::type>
template <class Container, typename... Args, std::enable_if_t<
std::is_integral<typename Container::value_type>::value &&
std::is_constructible<T, Args...>::value,
int> = 0>
WrappedPositional(const Position &p, const Position &boundary1, const Position &boundary2, const Container &dimensions,
Args&&... T_args)
: WrappedPositionalBase(p, boundary1, boundary2, dimensions), T(std::forward<Args>(T_args)...)
......@@ -335,7 +333,7 @@ class WrappedPositional : public WrappedPositionalBase, public T {
* \throws std::length_error if `p`, `boundary1`, and `boundary2` are not of the same dimension.
* \throws std::out_of_range if any element of `dims` is not a valid dimension index.
*/
template <typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
template <typename... Args, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
WrappedPositional(const Position &p, const Position &boundary1, const Position &boundary2, const std::initializer_list<size_t> &dims,
Args&&... T_args)
: WrappedPositionalBase(p, boundary1, boundary2, dims), T(std::forward<Args>(T_args)...)
......@@ -346,7 +344,7 @@ class WrappedPositional : public WrappedPositionalBase, public T {
*
* Any extra arguments are forwarded to T's constructor.
*/
template <typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
template <typename... Args, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
explicit WrappedPositional(const Position &p, Args&&... T_args)
: WrappedPositionalBase(p), T(std::forward<Args>(T_args)...)
{}
......
......@@ -37,7 +37,7 @@ namespace eris {
* will be in the same order as encountered in the input iterator.
*/
template <typename It>
typename std::enable_if<std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value>::type
std::enable_if_t<std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value>
all_combinations(
const It &begin,
const It &end,
......@@ -99,12 +99,11 @@ all_combinations(
* will execute the ... code 10 times with v set to: `{1,2,3}`, `{1,2,4}`, `{1,2,5}`, `{1,3,4}`,
* `{1,3,5}`, `{1,4,5}`, `{2,3,4}`, `{2,3,5}`, `{2,4,5}`, `{3,4,5}`.
*/
template <class BidirIt>
typename std::enable_if<
std::is_integral<typename BidirIt::value_type>::value and
template <class BidirIt, std::enable_if_t<
std::is_integral<typename BidirIt::value_type>::value &&
std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<BidirIt>::iterator_category>::value
, bool>::type
next_increasing_integer_permutation(BidirIt first, BidirIt last, typename BidirIt::value_type max) {
, int> = 0>
bool next_increasing_integer_permutation(BidirIt first, BidirIt last, typename BidirIt::value_type max) {
auto it = last;
--it;
while (true) {
......
......@@ -100,17 +100,17 @@ auto truncDist(
unsigned int precdf_draws = 0
)
#ifndef DOXYGEN_SHOULD_SEE_THIS
-> typename std::enable_if<
-> std::enable_if_t<
// Check that DistType and RNGType operate on the same type of floating-point variable:
std::is_same<typename DistType::value_type, typename RNGType::result_type>::value and
std::is_floating_point<typename DistType::value_type>::value and
std::is_same<typename DistType::value_type, typename RNGType::result_type>::value &&
std::is_floating_point<typename DistType::value_type>::value &&
// Check that the required cdf/quantile/complement ADL functions are callable
std::is_same<ResultType, decltype(cdf(dist, ResultType{}))>::value and
std::is_same<ResultType, decltype(cdf(complement(dist, ResultType{})))>::value and
std::is_same<ResultType, decltype(quantile(dist, ResultType{}))>::value and
std::is_same<ResultType, decltype(cdf(dist, ResultType{}))>::value &&
std::is_same<ResultType, decltype(cdf(complement(dist, ResultType{})))>::value &&
std::is_same<ResultType, decltype(quantile(dist, ResultType{}))>::value &&
std::is_same<ResultType, decltype(quantile(complement(dist, ResultType{})))>::value,
ResultType
>::type
>
#endif
{
if (min > max) throw std::range_error("truncDist() called with empty truncation range (min > max)");
......
......@@ -237,9 +237,9 @@ public:
* Throws std::logic_error if called after the header has been parsed or written.
*/
template <typename T>
typename std::enable_if<not std::is_const<T>::value>::type
addHeaderField(T &store) {
static_assert(serializer<T>::size > 0, "addHeaderField requires a fixed-size type");
void addHeaderField(T &store) {
static_assert(!std::is_const<T>::value, "addHeaderField() requires a non-const value reference");
static_assert(serializer<T>::size > 0, "addHeaderField() requires a fixed-size type");
if (header_fields_done_) throw std::logic_error("Cannot add header fields after the header has been read or written");
auto s = std::make_shared<serializer<T>>(store);
app_fields_.emplace_back(s);
......@@ -263,7 +263,7 @@ public:
*/
template <typename T>
void updateHeaderField(T &store) {
if (not header_fields_done_) return;
if (!header_fields_done_) return;
writef();
......
......@@ -95,12 +95,10 @@ std::istream& operator>>(std::istream &in, serializer_base &s);
/// Read a serialized value from an input stream, rvalue version
std::istream& operator>>(std::istream &in, serializer_base &&s);
template <typename T> using EnableFixedArithmetic = typename std::enable_if<
not std::is_const<T>::value and
std::is_arithmetic<T>::value>::type;
template <typename T> using EnableFixedConstArithmetic = typename std::enable_if<
std::is_const<T>::value and
std::is_arithmetic<T>::value>::type;
template <typename T> using EnableFixedArithmetic = std::enable_if_t<
!std::is_const<T>::value && std::is_arithmetic<T>::value>;
template <typename T> using EnableFixedConstArithmetic = std::enable_if_t<
std::is_const<T>::value && std::is_arithmetic<T>::value>;
#if not(defined(BOOST_LITTLE_ENDIAN) || defined(BOOST_BIG_ENDIAN))
#error System endianness not supported (neither big-byte nor little-byte endianness detected)!
......
......@@ -53,13 +53,13 @@ public:
MemberID(eris_id_t id) : id{id} {}
/// Implicit construction from anything with an `id()` method that returns an eris_id_t, most
/// notably Member (and derived)
template <typename T, typename std::enable_if<std::is_same<
decltype(std::declval<T>().id()), eris_id_t>::value, int>::type = 0>
template <typename T, std::enable_if_t<std::is_same<
decltype(std::declval<const T>().id()), eris_id_t>::value, int> = 0>
MemberID(const T &member) : id{member.id()} {}
/// Implicit construction from anything with a `->id()` indirect method that returns an
/// eris_id_t, most notably SharedMember<T> and Member pointer
template <typename T, typename std::enable_if<std::is_same<
decltype(std::declval<T>()->id()), eris_id_t>::value, int>::type = 0>
template <typename T, std::enable_if_t<std::is_same<
decltype(std::declval<const T>()->id()), eris_id_t>::value, int> = 0>
MemberID(const T &shared_member) : id{shared_member->id()} {}
/// Implicit conversion to an eris_id_t
......
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