diff --git a/include/boost/serialization/factory.hpp b/include/boost/serialization/factory.hpp index 8b092cba6..a73f8202a 100644 --- a/include/boost/serialization/factory.hpp +++ b/include/boost/serialization/factory.hpp @@ -21,6 +21,8 @@ #include #include +#include +#include #include namespace std{ @@ -59,15 +61,15 @@ namespace serialization { \ return new T( \ BOOST_PP_IF(BOOST_PP_GREATER(N, 0) \ , a0, BOOST_PP_EMPTY()) \ - BOOST_PP_IF(BOOST_PP_GREATER(N, 1)) \ + BOOST_PP_IF(BOOST_PP_GREATER(N, 1) \ , BOOST_PP_COMMA, BOOST_PP_EMPTY)() \ BOOST_PP_IF(BOOST_PP_GREATER(N, 1) \ , a1, BOOST_PP_EMPTY()) \ - BOOST_PP_IF(BOOST_PP_GREATER(N, 2)) \ + BOOST_PP_IF(BOOST_PP_GREATER(N, 2) \ , BOOST_PP_COMMA, BOOST_PP_EMPTY)() \ BOOST_PP_IF(BOOST_PP_GREATER(N, 2) \ , a2, BOOST_PP_EMPTY()) \ - BOOST_PP_IF(BOOST_PP_GREATER(N, 3)) \ + BOOST_PP_IF(BOOST_PP_GREATER(N, 3) \ , BOOST_PP_COMMA, BOOST_PP_EMPTY)() \ BOOST_PP_IF(BOOST_PP_GREATER(N, 3) \ , a3, BOOST_PP_EMPTY()) \ diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b0ed98126..f59191885 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -164,6 +164,7 @@ if ! $(BOOST_ARCHIVE_LIST) { [ test-bsl-run test_iterators : : : [ requires std_wstreambuf ] ] [ test-bsl-run test_iterators_base64 ] [ test-bsl-run test_iterators_copy ] + [ test-bsl-run test_factory ] [ test-bsl-run test_smart_cast ] [ test-bsl-run test_codecvt_null ] [ test-bsl-run test_singleton ] diff --git a/test/test_factory.cpp b/test/test_factory.cpp new file mode 100644 index 000000000..d94111a2a --- /dev/null +++ b/test/test_factory.cpp @@ -0,0 +1,108 @@ +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// test_factory.cpp + +// Copyright 2026 Gennaro Prota. +// 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) + +// See http://www.boost.org for updates, documentation, and revision history. + +// BOOST_SERIALIZATION_FACTORY builds an object from the arguments an +// extended_type_info was asked to construct it with. Only the arity zero +// form was ever used in the library, so the others went untested. + +// Reported by ivytin in +// https://github.com/boostorg/serialization/issues/215: a misplaced +// closing parenthesis kept every arity above zero from preprocessing at +// all. Thanks for spotting it, and for pinning down which parenthesis. + +// The arguments travel through a va_list, so they are limited to what +// survives the default argument promotions. A class type would not, which +// is why the ones below are all int and double. + +#include +#include + +#include +#include +#include +#include + +#include "test_tools.hpp" + +struct arg0 { + arg0() : sum(0) {} + int sum; +}; + +struct arg1 { + explicit arg1(int a) : sum(a) {} + int sum; +}; + +struct arg2 { + arg2(int a, int b) : sum(a + b) {} + int sum; +}; + +struct arg3 { + arg3(int a, int b, int c) : sum(a + b + c) {} + int sum; +}; + +struct arg4 { + arg4(int a, int b, int c, double d) + : sum(a + b + c + static_cast(d)) {} + int sum; +}; + +BOOST_SERIALIZATION_FACTORY_0(arg0) +BOOST_SERIALIZATION_FACTORY_1(arg1, int) +BOOST_SERIALIZATION_FACTORY_2(arg2, int, int) +BOOST_SERIALIZATION_FACTORY_3(arg3, int, int, int) +BOOST_SERIALIZATION_FACTORY_4(arg4, int, int, int, double) + +template +static const boost::serialization::extended_type_info & eti_of(){ + return boost::serialization::singleton< + boost::serialization::extended_type_info_typeid + >::get_const_instance(); +} + +// construct() hands back a raw pointer it has just newed, so adopt it +template +static std::unique_ptr owned(void * p){ + return std::unique_ptr(static_cast(p)); +} + +// construct() takes the count and then the arguments themselves, so the +// factory is reached the way the library reaches it +int +test_main(int /* argc */, char * /* argv */ []) +{ + const std::unique_ptr a0(owned(eti_of().construct(0))); + BOOST_REQUIRE(NULL != a0.get()); + BOOST_CHECK(0 == a0->sum); + + const std::unique_ptr a1(owned(eti_of().construct(1, 7))); + BOOST_REQUIRE(NULL != a1.get()); + BOOST_CHECK(7 == a1->sum); + + const std::unique_ptr a2( + owned(eti_of().construct(2, 7, 11))); + BOOST_REQUIRE(NULL != a2.get()); + BOOST_CHECK(18 == a2->sum); + + const std::unique_ptr a3( + owned(eti_of().construct(3, 7, 11, 13))); + BOOST_REQUIRE(NULL != a3.get()); + BOOST_CHECK(31 == a3->sum); + + const std::unique_ptr a4( + owned(eti_of().construct(4, 7, 11, 13, 2.0))); + BOOST_REQUIRE(NULL != a4.get()); + BOOST_CHECK(33 == a4->sum); + + return EXIT_SUCCESS; +}