Workaround compiler issues (constant conditions, compiler bugs...)

MSVC has issues with a tuple of references of incomplete classes and `virtual ~value() = default;`
Some compilers warn for constant expressions in the for-loop-condition
This commit is contained in:
Alexander Grund 2022-02-05 20:22:08 +01:00
parent fca30e7780
commit baaaa15489
No known key found for this signature in database
GPG key ID: AA48A0760367A42B
3 changed files with 70 additions and 48 deletions

View file

@ -62,6 +62,27 @@ namespace mock { namespace detail {
action_type a_;
};
/// Type erased value storage
struct value
{
value() = default;
value(const value&) = delete;
value& operator=(const value&) = delete;
virtual ~value() = default;
};
/// Actual value storage,
/// holds an instance of T (stripped of reference qualifiers)
template<typename T>
struct value_imp : value
{
using type = std::remove_const_t<std::remove_reference_t<T>>;
template<typename U>
value_imp(U&& t) : t_(std::forward<U>(t))
{}
type t_;
};
template<typename Result, typename Signature>
class action : public action_base<Result, Signature>
{
@ -85,24 +106,6 @@ namespace mock { namespace detail {
}
private:
struct value
{
value() = default;
value(const value&) = delete;
value& operator=(const value&) = delete;
virtual ~value() = default;
};
template<typename T>
struct value_imp : value
{
typedef std::remove_const_t<std::remove_reference_t<T>> type;
template<typename U>
value_imp(U&& t) : t_(std::forward<U>(t))
{}
type t_;
};
template<typename T>
typename value_imp<T>::type& store(T&& t)
{

View file

@ -27,7 +27,8 @@ namespace mock { namespace detail {
bool operator()(typename ref_arg<Args>::type...) override { return true; }
void serialize(std::ostream& s) const override
{
for(unsigned i = 0; i < sizeof...(Args); ++i)
constexpr auto arity = sizeof...(Args);
for(unsigned i = 0; i < arity; ++i)
{
if(i)
s << ", ";
@ -99,7 +100,7 @@ namespace mock { namespace detail {
template<typename R, typename... Args>
class expectation<R(Args...)> : public action<R, R(Args...)>
{
static constexpr auto arity = sizeof...(Args);
static constexpr std::size_t arity = sizeof...(Args);
public:
expectation() : expectation("unknown location", 0) {}
@ -122,13 +123,13 @@ namespace mock { namespace detail {
void invoke(std::unique_ptr<invocation> i) { invocation_ = std::move(i); }
template<typename... Constraints>
std::enable_if_t<(arity > 0) && sizeof...(Constraints) == arity, expectation&> with(Constraints... c)
std::enable_if_t<(arity > 0u) && sizeof...(Constraints) == arity, expectation&> with(Constraints... c)
{
matcher_ = std::make_unique<single_matcher<void(Constraints...), Args...>>(c...);
return *this;
}
template<typename Constraint, std::size_t Arity = arity>
std::enable_if_t<(Arity > 1), expectation&> with(const Constraint& c)
std::enable_if_t<(Arity > 1u), expectation&> with(const Constraint& c)
{
matcher_ = std::make_unique<multi_matcher<Constraint, Args...>>(c);
return *this;

View file

@ -69,6 +69,9 @@ namespace mock { namespace detail {
#endif
}
template<typename... Arg>
class lazy_args;
template<typename Signature>
class function_impl;
@ -133,7 +136,7 @@ namespace mock { namespace detail {
{
private:
typedef wrapper_base<R, expectation_type> base_type;
static constexpr auto arity = sizeof...(Args);
static constexpr std::size_t arity = sizeof...(Args);
public:
wrapper(const std::shared_ptr<mutex>& m, expectation_type& e) : base_type(e), lock_(m) {}
@ -239,7 +242,8 @@ namespace mock { namespace detail {
{
// Due to lifetime rules of references this must be created and consumed in one line
#define MOCK_FUNCTION_CONTEXT \
boost::unit_test::lazy_ostream::instance() << lazy_context(this) << lazy_args(args...) << lazy_expectations(this)
boost::unit_test::lazy_ostream::instance() \
<< lazy_context(this) << lazy_args<Args...>(args...) << lazy_expectations(this)
lock _(mutex_);
valid_ = false;
@ -316,35 +320,49 @@ namespace mock { namespace detail {
const function_impl* impl_;
};
struct lazy_args
{
lazy_args(std::add_lvalue_reference_t<Args>... args) : args_(args...) {}
friend std::ostream& operator<<(std::ostream& s, const lazy_args& a)
{
return a.print_impl(std::make_index_sequence<sizeof...(Args)>{}, s);
}
private:
std::tuple<std::add_lvalue_reference_t<Args>...> args_;
template<std::size_t... I>
std::ostream& print_impl(std::index_sequence<I...>, std::ostream& s) const
{
s << '(';
using expander = int[];
(void)expander{
0, (s << ' ' << mock::format(std::get<I>(args_)) << (sizeof...(Args) - 1u == I ? ' ' : ','), 0)...
};
return s << ')';
}
};
std::list<expectation_type> expectations_;
context* context_;
mutable bool valid_;
const int exceptions_;
const std::shared_ptr<mutex> mutex_;
};
template<typename ArgFirst, typename... ArgRest>
class lazy_args<ArgFirst, ArgRest...> : lazy_args<ArgRest...>
{
ArgFirst& arg_;
public:
lazy_args(ArgFirst& arg, std::add_lvalue_reference_t<ArgRest>... args)
: lazy_args<ArgRest...>(args...), arg_(arg)
{}
std::ostream& print(std::ostream& s) const
{
s << ' ' << mock::format(arg_) << ',';
return lazy_args<ArgRest...>::print(s);
}
};
template<typename ArgFirst>
class lazy_args<ArgFirst>
{
ArgFirst& arg_;
public:
lazy_args(ArgFirst& arg) : arg_(arg) {}
std::ostream& print(std::ostream& s) const { return s << ' ' << mock::format(arg_) << ' '; }
};
template<>
class lazy_args<>
{
public:
std::ostream& print(std::ostream& s) const { return s; }
};
template<typename... Args>
std::ostream& operator<<(std::ostream& s, const lazy_args<Args...>& a)
{
s << '(';
return a.print(s) << ')';
}
}} // namespace mock::detail
#endif // MOCK_FUNCTION_IMPL_HPP_INCLUDED