diff --git a/.github/workflows/linux-full-tests.yml b/.github/workflows/linux-full-tests.yml index 741b9a76b65..d84b65a57e4 100644 --- a/.github/workflows/linux-full-tests.yml +++ b/.github/workflows/linux-full-tests.yml @@ -97,7 +97,7 @@ jobs: tag: rolling cc: gcc cxx: g++ - cxxflags: "-std=c++11" + cxxflags: "-std=c++11 -Wno-cpp" - name: "C++14 mode" shortname: c++14 tag: rolling @@ -164,6 +164,12 @@ jobs: cc: gcc cxx: g++ configureflags: --enable-openmp + - name: "Null as function template" + shortname: nullfunctions + tag: rolling + cc: gcc + cxx: g++ + configureflags: --enable-null-as-functions container: ghcr.io/lballabio/quantlib-devenv:${{ matrix.tag }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/linux-nondefault.yml b/.github/workflows/linux-nondefault.yml index f51e675a093..db3d61bc419 100644 --- a/.github/workflows/linux-nondefault.yml +++ b/.github/workflows/linux-nondefault.yml @@ -149,7 +149,7 @@ jobs: - name: Build run: | ./autogen.sh - ./configure --disable-static --enable-error-lines --enable-error-functions --enable-tracing --enable-indexed-coupons --enable-extra-safety-checks --enable-sessions --enable-thread-safe-observer-pattern --enable-intraday ${{ matrix.configureflags }} CC="ccache ${{ matrix.cc }}" CXX="ccache ${{ matrix.cxx }}" CXXFLAGS="-O2 -g0 -Wall -Wno-unknown-pragmas -Werror ${{ matrix.cxxflags }}" + ./configure --disable-static --enable-error-lines --enable-error-functions --enable-tracing --enable-indexed-coupons --enable-extra-safety-checks --enable-sessions --enable-thread-safe-observer-pattern --enable-intraday --enable-null-as-functions ${{ matrix.configureflags }} CC="ccache ${{ matrix.cc }}" CXX="ccache ${{ matrix.cxx }}" CXXFLAGS="-O2 -g0 -Wall -Wno-unknown-pragmas -Werror ${{ matrix.cxxflags }}" make -j 2 - name: Run tests run: | diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index c7bbcae4208..b73faad25bb 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -99,7 +99,7 @@ jobs: tag: rolling cc: gcc cxx: g++ - cxxflags: "-std=c++11" + cxxflags: "-std=c++11 -Wno-cpp" - name: "C++14 mode" shortname: c++14 tag: rolling @@ -180,6 +180,13 @@ jobs: cxx: g++ configureflags: --enable-parallel-unit-test-runner moreflags: -lrt + - name: "Null as function template" + shortname: nullfunctions + tag: rolling + cc: gcc + cxx: g++ + configureflags: --enable-null-as-functions + tests: true container: ghcr.io/lballabio/quantlib-devenv:${{ matrix.tag }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/macos-nondefault.yml b/.github/workflows/macos-nondefault.yml index afbabbe2d00..6d0488411a5 100644 --- a/.github/workflows/macos-nondefault.yml +++ b/.github/workflows/macos-nondefault.yml @@ -43,7 +43,7 @@ jobs: - name: Build run: | ./autogen.sh - ./configure --disable-shared --enable-error-lines --enable-error-functions --enable-tracing --enable-indexed-coupons --enable-extra-safety-checks --enable-sessions --enable-thread-safe-observer-pattern --enable-intraday ${{ matrix.configureflags }} CC="ccache clang" CXX="ccache clang++" CXXFLAGS="-O2 -g0 -Wall -Werror -stdlib=libc++ -mmacosx-version-min=10.9 ${{ matrix.cxxflags }}" LDFLAGS="-stdlib=libc++ -mmacosx-version-min=10.9" + ./configure --disable-shared --enable-error-lines --enable-error-functions --enable-tracing --enable-indexed-coupons --enable-extra-safety-checks --enable-sessions --enable-thread-safe-observer-pattern --enable-intraday --enable-null-as-functions ${{ matrix.configureflags }} CC="ccache clang" CXX="ccache clang++" CXXFLAGS="-O2 -g0 -Wall -Werror -stdlib=libc++ -mmacosx-version-min=10.9 ${{ matrix.cxxflags }}" LDFLAGS="-stdlib=libc++ -mmacosx-version-min=10.9" make -j 2 - name: Run tests run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 915c8ceb9a0..896853e04a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ option(QL_ERROR_FUNCTIONS "Error messages should include current function inform option(QL_ERROR_LINES "Error messages should include file and line information" OFF) option(QL_EXTRA_SAFETY_CHECKS "Extra safety checks should be performed" OFF) option(QL_HIGH_RESOLUTION_DATE "Enable date resolution down to microseconds" OFF) +option(QL_NULL_AS_FUNCTIONS "Enable the implementation of Null as template functions" OFF) option(QL_INSTALL_BENCHMARK "Install benchmark" ON) option(QL_INSTALL_EXAMPLES "Install examples" ON) option(QL_INSTALL_TEST_SUITE "Install test suite" ON) diff --git a/CMakePresets.json b/CMakePresets.json index f436a7439a7..92a0f744a5d 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -109,6 +109,7 @@ "QL_ENABLE_SESSIONS": "ON", "QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN": "ON", "QL_HIGH_RESOLUTION_DATE": "ON", + "QL_NULL_AS_FUNCTIONS": "ON", "QL_USE_INDEXED_COUPON": "ON", "QL_USE_STD_CLASSES": "ON" } @@ -126,6 +127,7 @@ "QL_ENABLE_SESSIONS": "ON", "QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN": "ON", "QL_HIGH_RESOLUTION_DATE": "ON", + "QL_NULL_AS_FUNCTIONS": "ON", "QL_USE_INDEXED_COUPON": "ON", "QL_USE_STD_CLASSES": "ON" }, diff --git a/Docs/pages/config.docs b/Docs/pages/config.docs index 4cc7fe7bb96..d0720869bd9 100644 --- a/Docs/pages/config.docs +++ b/Docs/pages/config.docs @@ -127,6 +127,15 @@ are used instead of `boost::tuple`. If disabled (the default) the Boost facilities are used. + \code + #define QL_NULL_AS_FUNCTIONS + \endcode + If defined, `Null` will be implemented as a set of template + functions. This allows the code to work with user-defined `Real` + types but was reported to cause internal compiler errors with + Visual C++ 2022 in some cases. If disabled (the default) `Null` + will be implemented as a class template, as in previous releases. + \code #define QL_ENABLE_PARALLEL_UNIT_TEST_RUNNER \endcode diff --git a/configure.ac b/configure.ac index 0897959a538..5b420eb858c 100644 --- a/configure.ac +++ b/configure.ac @@ -391,7 +391,6 @@ if test "$ql_use_std_function" = "yes" ; then fi AC_MSG_RESULT([$ql_use_std_function]) - AC_MSG_CHECKING([whether to enable std::tuple]) AC_ARG_ENABLE([std-tuple], AS_HELP_STRING([--enable-std-tuple], @@ -426,6 +425,25 @@ if test "$ql_use_std_classes" = "yes" ; then fi AC_MSG_RESULT([$ql_use_std_classes]) +AC_MSG_CHECKING([whether to enable the implementation of Null as template functions]) +AC_ARG_ENABLE([null-as-functions], + AS_HELP_STRING([--enable-null-as-functions], + [If enabled, Null will be implemented as a set + of template functions. This allows the code + to work with user-defined Real types but was + reported to cause internal compiler errors + with Visual C++ 2022 in some cases. + If disabled (the default) Null will be + implemented as a class template, as in + previous releases.]), + [ql_use_null_functions=$enableval], + [ql_use_null_functions=no]) +if test "$ql_use_null_functions" = "yes" ; then + AC_DEFINE([QL_NULL_AS_FUNCTIONS],[1], + [Define this if you want to enable the implementation of Null as template functions.]) +fi +AC_MSG_RESULT([$ql_use_null_functions]) + # manual configurations for specific hosts case $host in diff --git a/ql/config.hpp.cfg b/ql/config.hpp.cfg index 25b3bd6129b..bea1d2340de 100644 --- a/ql/config.hpp.cfg +++ b/ql/config.hpp.cfg @@ -40,5 +40,6 @@ #cmakedefine QL_USE_STD_SHARED_PTR #cmakedefine QL_USE_STD_FUNCTION #cmakedefine QL_USE_STD_TUPLE +#cmakedefine QL_NULL_AS_FUNCTIONS #endif diff --git a/ql/math/array.hpp b/ql/math/array.hpp index 8322267c11e..c31d04c765b 100644 --- a/ql/math/array.hpp +++ b/ql/math/array.hpp @@ -145,13 +145,25 @@ namespace QuantLib { Size n_; }; + #ifdef QL_NULL_AS_FUNCTIONS + //! specialization of null template for this class template <> inline Array Null() { return {}; } + #else + + //! specialization of null template for this class + template <> + class Null { + public: + Null() = default; + operator Array() const { return Array(); } + }; + #endif /*! \relates Array */ Real DotProduct(const Array&, const Array&); diff --git a/ql/prices.hpp b/ql/prices.hpp index 011c334e517..2a9c654adb4 100644 --- a/ql/prices.hpp +++ b/ql/prices.hpp @@ -100,12 +100,25 @@ namespace QuantLib { Real open_, close_, high_, low_; }; - + #ifdef QL_NULL_AS_FUNCTIONS + template <> inline IntervalPrice Null() { return {}; }; + #else + + template <> + class Null + { + public: + Null() = default; + operator IntervalPrice() const { return {}; } + }; + + #endif + } #endif diff --git a/ql/time/date.hpp b/ql/time/date.hpp index 071f31106ff..e32671df790 100644 --- a/ql/time/date.hpp +++ b/ql/time/date.hpp @@ -370,12 +370,24 @@ namespace QuantLib { } + #ifdef QL_NULL_AS_FUNCTIONS + //! specialization of Null template for the Date class template <> inline Date Null() { return {}; } + #else + + template <> + class Null { + public: + Null() = default; + operator Date() const { return {}; } + }; + + #endif #ifndef QL_HIGH_RESOLUTION_DATE // inline definitions diff --git a/ql/userconfig.hpp b/ql/userconfig.hpp index 5d926cd34c8..a3222533ff9 100644 --- a/ql/userconfig.hpp +++ b/ql/userconfig.hpp @@ -101,6 +101,11 @@ //# define QL_USE_STD_TUPLE #endif +/* Define this to enable the implementation of Null as template functions. */ +#ifndef QL_NULL_AS_FUNCTIONS +//# define QL_NULL_AS_FUNCTIONS +#endif + /* Define this to enable the parallel unit test runner */ #ifndef QL_ENABLE_PARALLEL_UNIT_TEST_RUNNER //# define QL_ENABLE_PARALLEL_UNIT_TEST_RUNNER diff --git a/ql/utilities/null.hpp b/ql/utilities/null.hpp index 35031e2b22f..2c6b70a422a 100644 --- a/ql/utilities/null.hpp +++ b/ql/utilities/null.hpp @@ -32,8 +32,6 @@ namespace QuantLib { - - namespace detail { template @@ -59,12 +57,32 @@ namespace QuantLib { } + #ifdef QL_NULL_AS_FUNCTIONS + //! template function providing a null value for a given type. template T Null() { return T(detail::FloatingPointNull::value>::nullValue()); } + #else + + //! template class providing a null value for a given type. + template + class Null; + + // default implementation for built-in types + template + class Null { + public: + Null() = default; + operator T() const { + return T(detail::FloatingPointNull::value>::nullValue()); + } + }; + + #endif + }