mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 04:22:12 +00:00
static checks for invalid method params
This commit is contained in:
@@ -301,7 +301,7 @@ constexpr bool is_virtual_ptr = detail::is_virtual_ptr_aux<T>::value;
|
||||
|
||||
void boost_openmethod_vptr(...);
|
||||
|
||||
template<class Registry, class Class>
|
||||
template<class Class, class Registry>
|
||||
constexpr bool has_vptr_fn = std::is_same_v<
|
||||
decltype(boost_openmethod_vptr(
|
||||
std::declval<const Class&>(), std::declval<Registry*>())),
|
||||
@@ -311,7 +311,7 @@ template<class Registry, class ArgType>
|
||||
decltype(auto) acquire_vptr(const ArgType& arg) {
|
||||
Registry::check_initialized();
|
||||
|
||||
if constexpr (detail::has_vptr_fn<Registry, ArgType>) {
|
||||
if constexpr (detail::has_vptr_fn<ArgType, Registry>) {
|
||||
return boost_openmethod_vptr(arg, static_cast<Registry*>(nullptr));
|
||||
} else {
|
||||
return Registry::template policy<policies::vptr>::dynamic_vptr(arg);
|
||||
@@ -974,6 +974,16 @@ template<class Registry, typename Type, class OtherRegistry>
|
||||
struct using_same_registry<Registry, const virtual_ptr<Type, OtherRegistry>&>
|
||||
: std::is_same<Registry, OtherRegistry> {};
|
||||
|
||||
template<typename, class>
|
||||
struct valid_method_parameter : std::true_type {};
|
||||
|
||||
template<typename T, class Registry>
|
||||
struct valid_method_parameter<virtual_<T>, Registry>
|
||||
: std::bool_constant<
|
||||
has_vptr_fn<virtual_type<T, Registry>, Registry> ||
|
||||
Registry::rtti::template is_polymorphic<
|
||||
virtual_type<T, Registry>>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<
|
||||
@@ -1003,10 +1013,15 @@ class method<Name, auto(Parameters...)->ReturnType, Registry>
|
||||
mp11::mp_list<Parameters...>, detail::is_virtual>::value;
|
||||
|
||||
// sanity checks
|
||||
static_assert(Arity > 0, "method must have at least one virtual argument");
|
||||
static_assert(Arity > 0, "method has no virtual parameters");
|
||||
static_assert(
|
||||
(true && ... &&
|
||||
detail::using_same_registry<Registry, Parameters>::value));
|
||||
(... && detail::using_same_registry<Registry, Parameters>::value),
|
||||
"method and parameters use different registries");
|
||||
static_assert(
|
||||
(... && detail::valid_method_parameter<Parameters, Registry>::value),
|
||||
"virtual_<> parameter is not polymorphic and no boost_openmethod_vptr "
|
||||
"function is available");
|
||||
//static_assert()
|
||||
|
||||
type_id vp_type_ids[Arity];
|
||||
|
||||
|
||||
12
test/compile_fail_bad_virtual_parameter.cpp
Normal file
12
test/compile_fail_bad_virtual_parameter.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// 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 <boost/openmethod.hpp>
|
||||
|
||||
using boost::openmethod::virtual_;
|
||||
|
||||
struct Cat {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_<Cat>), void);
|
||||
12
test/compile_fail_virtual_ptr_different_registries.cpp
Normal file
12
test/compile_fail_virtual_ptr_different_registries.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// 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 <boost/openmethod.hpp>
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Cat {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_ptr<Cat, release_registry>), void, debug_registry);
|
||||
@@ -231,7 +231,9 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a_b1_c) {
|
||||
B1 C
|
||||
*/
|
||||
|
||||
struct A {};
|
||||
struct A {
|
||||
virtual ~A() = default;
|
||||
};
|
||||
struct B : A {};
|
||||
struct C : A {};
|
||||
|
||||
@@ -258,7 +260,9 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_b1_c1) {
|
||||
B1 C1
|
||||
*/
|
||||
|
||||
struct A {};
|
||||
struct A {
|
||||
virtual ~A() = default;
|
||||
};
|
||||
struct B : A {};
|
||||
struct C : A {};
|
||||
|
||||
@@ -294,7 +298,9 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_b1_d1_c1_d1) {
|
||||
D1
|
||||
*/
|
||||
|
||||
struct A {};
|
||||
struct A {
|
||||
virtual ~A() = default;
|
||||
};
|
||||
struct B : virtual A {};
|
||||
struct C : virtual A {};
|
||||
struct D : B, C {};
|
||||
@@ -338,7 +344,9 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_b1_d1_c1_d1_e2) {
|
||||
D1 E2 but E can use them
|
||||
*/
|
||||
|
||||
struct A {};
|
||||
struct A {
|
||||
virtual ~A() = default;
|
||||
};
|
||||
struct B : virtual A {};
|
||||
struct C : virtual A {};
|
||||
struct E : C {};
|
||||
@@ -396,8 +404,12 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_c1_b1) {
|
||||
C1
|
||||
*/
|
||||
|
||||
struct A {};
|
||||
struct B {};
|
||||
struct A {
|
||||
virtual ~A() = default;
|
||||
};
|
||||
struct B {
|
||||
virtual ~B() = default;
|
||||
};
|
||||
struct C : A, B {};
|
||||
|
||||
BOOST_OPENMETHOD_REGISTER(use_classes<A, test_registry>);
|
||||
|
||||
@@ -16,6 +16,7 @@ using namespace boost::openmethod::detail;
|
||||
namespace mp11 = boost::mp11;
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/with_vptr.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
@@ -138,6 +139,28 @@ static_assert(detail::using_same_registry<registry1, int>::value);
|
||||
static_assert(
|
||||
!detail::using_same_registry<registry1, virtual_ptr<a, registry2>>::value);
|
||||
|
||||
static_assert(valid_method_parameter<default_registry, virtual_<a&>>::value);
|
||||
static_assert(
|
||||
valid_method_parameter<default_registry, virtual_<const a&>>::value);
|
||||
static_assert(valid_method_parameter<default_registry, int>::value);
|
||||
|
||||
struct non_polymorphic {};
|
||||
|
||||
static_assert(!valid_method_parameter<
|
||||
virtual_<non_polymorphic&>, default_registry>::value);
|
||||
|
||||
struct non_polymorphic_with_vptr {};
|
||||
|
||||
auto boost_openmethod_vptr(const non_polymorphic_with_vptr&, void*)
|
||||
-> vptr_type;
|
||||
|
||||
static_assert(valid_method_parameter<
|
||||
virtual_<non_polymorphic_with_vptr&>, default_registry>::value);
|
||||
|
||||
static_assert(
|
||||
valid_method_parameter<
|
||||
virtual_<const non_polymorphic_with_vptr&>, default_registry>::value);
|
||||
|
||||
// clang-format on
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
@@ -314,7 +337,7 @@ struct Animal {
|
||||
friend auto boost_openmethod_vptr(const Animal&, void*) -> vptr_type;
|
||||
};
|
||||
|
||||
static_assert(detail::has_vptr_fn<default_registry, Animal>);
|
||||
static_assert(detail::has_vptr_fn<Animal, default_registry>);
|
||||
|
||||
} // namespace TEST_NS
|
||||
|
||||
@@ -330,8 +353,8 @@ struct Animal {
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(detail::has_vptr_fn<test_registry, Animal>);
|
||||
static_assert(!detail::has_vptr_fn<default_registry, Animal>);
|
||||
static_assert(detail::has_vptr_fn<Animal, test_registry>);
|
||||
static_assert(!detail::has_vptr_fn<Animal, default_registry>);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(vptr_from_function) {
|
||||
initialize<test_registry>();
|
||||
|
||||
@@ -17,74 +17,87 @@ struct test_registry
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/with_vptr.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/compiler.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE intrusive
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/tools/output_test_stream.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
namespace bom = boost::openmethod;
|
||||
using bom::virtual_;
|
||||
|
||||
struct Animal : bom::with_vptr<Animal> {
|
||||
Animal();
|
||||
explicit Animal(std::ostream& os);
|
||||
~Animal();
|
||||
std::ostream& os;
|
||||
};
|
||||
|
||||
struct Cat : Animal, bom::with_vptr<Cat, Animal> {
|
||||
Cat();
|
||||
explicit Cat(std::ostream& os);
|
||||
~Cat();
|
||||
};
|
||||
|
||||
struct Pet : bom::with_vptr<Pet> {
|
||||
Pet();
|
||||
explicit Pet(std::ostream& os);
|
||||
~Pet();
|
||||
std::string name;
|
||||
std::ostream& os;
|
||||
};
|
||||
|
||||
struct DomesticCat : Cat, Pet, bom::with_vptr<DomesticCat, Cat, Pet> {
|
||||
DomesticCat();
|
||||
explicit DomesticCat(std::ostream& os);
|
||||
~DomesticCat();
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
speak, (virtual_<const Animal&> animal, std::ostream& os), void);
|
||||
|
||||
BOOST_OPENMETHOD(describe, (virtual_<const Pet&> pet, std::ostream& os), void);
|
||||
|
||||
Animal::Animal() {
|
||||
speak(*this, std::cout);
|
||||
BOOST_OPENMETHOD(
|
||||
meet,
|
||||
(virtual_<std::shared_ptr<Animal>>,
|
||||
virtual_<const std::shared_ptr<Animal>&>, std::ostream& os),
|
||||
void);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
meet,
|
||||
(std::shared_ptr<Animal>, const std::shared_ptr<Animal>&, std::ostream& os),
|
||||
void) {
|
||||
os << "ignore\n";
|
||||
}
|
||||
|
||||
Animal::Animal(std::ostream& os) : os(os) {
|
||||
speak(*this, os);
|
||||
}
|
||||
|
||||
Animal::~Animal() {
|
||||
speak(*this, std::cout);
|
||||
speak(*this, os);
|
||||
}
|
||||
|
||||
Cat::Cat() {
|
||||
speak(*this, std::cout);
|
||||
Cat::Cat(std::ostream& os) : Animal(os) {
|
||||
speak(*this, os);
|
||||
}
|
||||
|
||||
Cat::~Cat() {
|
||||
speak(*this, std::cout);
|
||||
speak(*this, os);
|
||||
}
|
||||
|
||||
Pet::Pet() {
|
||||
describe(*this, std::cout);
|
||||
Pet::Pet(std::ostream& os) : os(os) {
|
||||
describe(*this, os);
|
||||
}
|
||||
|
||||
Pet::~Pet() {
|
||||
describe(*this, std::cout);
|
||||
describe(*this, os);
|
||||
}
|
||||
|
||||
DomesticCat::DomesticCat() {
|
||||
DomesticCat::DomesticCat(std::ostream& os) : Cat(os), Pet(os) {
|
||||
name = "Felix";
|
||||
describe(*this, std::cout);
|
||||
describe(*this, os);
|
||||
}
|
||||
|
||||
DomesticCat::~DomesticCat() {
|
||||
name = "Felix";
|
||||
describe(*this, std::cout);
|
||||
describe(*this, Cat::os);
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(speak, (const Animal&, std::ostream& os), void) {
|
||||
@@ -117,56 +130,53 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
BOOST_AUTO_TEST_CASE(intrusive_mode) {
|
||||
bom::initialize();
|
||||
|
||||
std::unique_ptr<DomesticCat> cat;
|
||||
std::shared_ptr<DomesticCat> cat;
|
||||
std::ostringstream cd_output;
|
||||
|
||||
{
|
||||
boost::test_tools::output_test_stream output;
|
||||
{
|
||||
capture_cout capture(output.rdbuf());
|
||||
cat = std::make_unique<DomesticCat>();
|
||||
}
|
||||
std::ostringstream output;
|
||||
cat = std::make_shared<DomesticCat>(cd_output);
|
||||
|
||||
BOOST_CHECK(output.is_equal(
|
||||
BOOST_TEST(
|
||||
cd_output.str() ==
|
||||
"???\n"
|
||||
"meow\n"
|
||||
"I am a pet\n"
|
||||
"I am Felix the cat\n"));
|
||||
"I am Felix the cat\n");
|
||||
}
|
||||
|
||||
{
|
||||
boost::test_tools::output_test_stream output;
|
||||
|
||||
{
|
||||
capture_cout capture(output.rdbuf());
|
||||
describe(*cat, std::cout);
|
||||
}
|
||||
|
||||
BOOST_CHECK(output.is_equal("I am Felix the cat\n"));
|
||||
std::ostringstream output;
|
||||
describe(*cat, output);
|
||||
BOOST_TEST(output.str() == "I am Felix the cat\n");
|
||||
}
|
||||
|
||||
{
|
||||
boost::test_tools::output_test_stream output;
|
||||
|
||||
{
|
||||
capture_cout capture(output.rdbuf());
|
||||
cat_influencer(*cat, std::cout);
|
||||
}
|
||||
|
||||
BOOST_CHECK(output.is_equal("Follow Felix the cat on YouTube\n"));
|
||||
std::ostringstream output;
|
||||
cat_influencer(*cat, output);
|
||||
BOOST_TEST(output.str() == "Follow Felix the cat on YouTube\n");
|
||||
}
|
||||
|
||||
{
|
||||
boost::test_tools::output_test_stream output;
|
||||
{
|
||||
capture_cout capture(output.rdbuf());
|
||||
cat.reset();
|
||||
}
|
||||
cd_output.str("");
|
||||
cat.reset();
|
||||
|
||||
BOOST_CHECK(output.is_equal(
|
||||
BOOST_TEST(
|
||||
cd_output.str() ==
|
||||
"I am Felix the cat\n"
|
||||
"I am a pet\n"
|
||||
"meow\n"
|
||||
"???\n"));
|
||||
"???\n");
|
||||
}
|
||||
|
||||
{
|
||||
auto felix = std::make_shared<Cat>(cd_output),
|
||||
sylvester = std::make_shared<Cat>(cd_output);
|
||||
|
||||
std::ostringstream output;
|
||||
meet(felix, sylvester, output);
|
||||
|
||||
BOOST_TEST(output.str() == "ignore\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user