mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-01-19 04:22:11 +00:00
Streamline some syntax and more cover
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
// Copyright 2011 John Maddock.
|
||||
// Copyright 2011 - 2025 John Maddock.
|
||||
// Copyright 2025 Christopher Kormanyos.
|
||||
// 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)
|
||||
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
@@ -10,7 +12,7 @@ template <class T>
|
||||
void calc_log2(T& num, unsigned digits)
|
||||
{
|
||||
using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
|
||||
using si_type = typename std::tuple_element<0, typename T::signed_types>::type ;
|
||||
using si_type = typename std::tuple_element<0, typename T::signed_types>::type;
|
||||
|
||||
//
|
||||
// String value with 1100 digits:
|
||||
@@ -219,14 +221,14 @@ void calc_pi(T& result, unsigned digits)
|
||||
template <class T>
|
||||
const T& get_constant_ln2()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = 0;
|
||||
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
boost::multiprecision::detail::maybe_promote_precision(&result);
|
||||
calc_log2(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
static const BOOST_MP_THREAD_LOCAL T result =
|
||||
[]()
|
||||
{
|
||||
T tmp_val;
|
||||
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
|
||||
calc_log2(tmp_val, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
return tmp_val;
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -234,14 +236,14 @@ const T& get_constant_ln2()
|
||||
template <class T>
|
||||
const T& get_constant_e()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = 0;
|
||||
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
boost::multiprecision::detail::maybe_promote_precision(&result);
|
||||
calc_e(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
static const BOOST_MP_THREAD_LOCAL T result =
|
||||
[]()
|
||||
{
|
||||
T tmp_val;
|
||||
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
|
||||
calc_e(tmp_val, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
return tmp_val;
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -249,17 +251,18 @@ const T& get_constant_e()
|
||||
template <class T>
|
||||
const T& get_constant_pi()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = 0;
|
||||
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
boost::multiprecision::detail::maybe_promote_precision(&result);
|
||||
calc_pi(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
static const BOOST_MP_THREAD_LOCAL T result =
|
||||
[]()
|
||||
{
|
||||
T tmp_val;
|
||||
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
|
||||
calc_pi(tmp_val, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
return tmp_val;
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
@@ -267,19 +270,22 @@ const T& get_constant_pi()
|
||||
template <class T>
|
||||
const T& get_constant_one_over_epsilon()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = 0;
|
||||
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
|
||||
boost::multiprecision::detail::maybe_promote_precision(&result);
|
||||
result = static_cast<ui_type>(1u);
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<number<T> >::is_specialized)
|
||||
eval_divide(result, std::numeric_limits<number<T> >::epsilon().backend());
|
||||
else
|
||||
eval_ldexp(result, result, boost::multiprecision::detail::digits2<number<T> >::value() - 1);
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
static const BOOST_MP_THREAD_LOCAL T result =
|
||||
[]()
|
||||
{
|
||||
using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
|
||||
|
||||
T tmp_val;
|
||||
boost::multiprecision::detail::maybe_promote_precision(&tmp_val);
|
||||
tmp_val = static_cast<ui_type>(1u);
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<number<T> >::is_specialized)
|
||||
eval_divide(tmp_val, std::numeric_limits<number<T> >::epsilon().backend());
|
||||
else
|
||||
eval_ldexp(tmp_val, tmp_val, boost::multiprecision::detail::digits2<number<T> >::value() - 1);
|
||||
|
||||
return tmp_val;
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// This work is based on an earlier work:
|
||||
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
|
||||
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
|
||||
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
@@ -99,7 +100,7 @@ inline void pow_imp(T& result, const T& t, const U& p, const std::integral_const
|
||||
{
|
||||
// Signed integer power, just take care of the sign then call the unsigned version:
|
||||
using int_type = typename boost::multiprecision::detail::canonical<U, T>::type;
|
||||
using ui_type = typename boost::multiprecision::detail::make_unsigned<U>::type ;
|
||||
using ui_type = typename boost::multiprecision::detail::make_unsigned<U>::type;
|
||||
|
||||
if (p < 0)
|
||||
{
|
||||
@@ -163,7 +164,7 @@ void hyp0F0(T& H0F0, const T& x)
|
||||
x_pow_n_div_n_fact.negate();
|
||||
}
|
||||
if (n >= series_limit)
|
||||
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge"));
|
||||
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge")); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -212,7 +213,7 @@ void hyp1F0(T& H1F0, const T& a, const T& x)
|
||||
break;
|
||||
}
|
||||
if (n >= series_limit)
|
||||
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge"));
|
||||
BOOST_MP_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge")); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -227,8 +228,8 @@ void eval_exp(T& result, const T& x)
|
||||
return;
|
||||
}
|
||||
using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
|
||||
using si_type = typename boost::multiprecision::detail::canonical<int, T>::type ;
|
||||
using exp_type = typename T::exponent_type ;
|
||||
using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
|
||||
using exp_type = typename T::exponent_type;
|
||||
using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
|
||||
|
||||
// Handle special arguments.
|
||||
@@ -373,10 +374,12 @@ void eval_log(T& result, const T& arg)
|
||||
// log(x) = log(2) * n + log1p(1 + y)
|
||||
//
|
||||
using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
|
||||
using exp_type = typename T::exponent_type ;
|
||||
using exp_type = typename T::exponent_type;
|
||||
using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
|
||||
using fp_type = typename std::tuple_element<0, typename T::float_types>::type ;
|
||||
int s = eval_signbit(arg);
|
||||
using fp_type = typename std::tuple_element<0, typename T::float_types>::type;
|
||||
|
||||
const int s = eval_signbit(arg);
|
||||
|
||||
switch (eval_fpclassify(arg))
|
||||
{
|
||||
case FP_NAN:
|
||||
@@ -455,16 +458,14 @@ void eval_log(T& result, const T& arg)
|
||||
template <class T>
|
||||
const T& get_constant_log10()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = 0;
|
||||
if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
|
||||
T ten;
|
||||
ten = ui_type(10u);
|
||||
eval_log(result, ten);
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
static const BOOST_MP_THREAD_LOCAL T result =
|
||||
[]()
|
||||
{
|
||||
const T ten(10);
|
||||
T tmp_val;
|
||||
eval_log(tmp_val, ten);
|
||||
return tmp_val;
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -555,7 +556,7 @@ inline void eval_pow(T& result, const T& x, const T& a)
|
||||
return;
|
||||
}
|
||||
}
|
||||
BOOST_MP_CATCH(const std::exception&)
|
||||
BOOST_MP_CATCH(const std::exception&) // LCOV_EXCL_LINE
|
||||
{
|
||||
// fallthrough..
|
||||
}
|
||||
@@ -679,7 +680,7 @@ inline void eval_pow(T& result, const T& x, const T& a)
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_MP_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type."));
|
||||
BOOST_MP_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type.")); // LCOV_EXCL_LINE
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -746,7 +747,7 @@ template <class T, class A>
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
|
||||
inline typename std::enable_if<!boost::multiprecision::detail::is_integral<A>::value, void>::type
|
||||
#else
|
||||
inline typename std::enable_if<is_compatible_arithmetic_type<A, number<T> >::value && !boost::multiprecision::detail::is_integral<A>::value, void>::type
|
||||
inline typename std::enable_if<boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<T> >::value && !boost::multiprecision::detail::is_integral<A>::value, void>::type
|
||||
#endif
|
||||
eval_pow(T& result, const T& x, const A& a)
|
||||
{
|
||||
@@ -763,7 +764,7 @@ template <class T, class A>
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
|
||||
inline void
|
||||
#else
|
||||
inline typename std::enable_if<is_compatible_arithmetic_type<A, number<T> >::value, void>::type
|
||||
inline typename std::enable_if<boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<T> >::value, void>::type
|
||||
#endif
|
||||
eval_pow(T& result, const A& x, const T& a)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
|
||||
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
|
||||
|
||||
#define TEST_CPP_BIN_FLOAT
|
||||
#define TEST_CPP_DEC_FLOAT
|
||||
#define TEST_CPP_DOUBLE_FLOAT
|
||||
#if defined(__GNUC__)
|
||||
#define TEST_FLOAT128
|
||||
#define TEST_MPF_50
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
@@ -66,13 +74,14 @@
|
||||
#include <boost/multiprecision/cpp_double_fp.hpp>
|
||||
#endif
|
||||
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
// These were the only ones I checked locally at the moment that use random tests.
|
||||
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
#include <random>
|
||||
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
|
||||
template<typename FloatType> auto my_zero() -> FloatType&;
|
||||
|
||||
@@ -127,7 +136,7 @@ namespace local {
|
||||
|
||||
} // namespace local
|
||||
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
|
||||
// These were the only ones I checked locally at the moment.
|
||||
|
||||
@@ -195,26 +204,26 @@ void test_small_a_in_default_ops()
|
||||
T("0.99999976301106994561811131758260769485991144451216442896857591003045319114657385381607667593523204524")
|
||||
}};
|
||||
|
||||
unsigned max_err = 0;
|
||||
unsigned max_err = 0U;
|
||||
|
||||
std::size_t k { UINT8_C(0) };
|
||||
const T x_val(T(789U) / 1000);
|
||||
|
||||
const T x_val { T { 789U } / 1000 };
|
||||
const T local_tol { std::numeric_limits<T>::epsilon() / 8 };
|
||||
|
||||
const T local_tol { std::numeric_limits<T>::epsilon() / 4 };
|
||||
T small_a = pow(T(10), -12);
|
||||
|
||||
for (int p10 = -12; p10 < -5; ++p10)
|
||||
for (std::size_t k { UINT8_C(0) }; k < std::tuple_size<small_a_data_array_type>::value; ++k)
|
||||
{
|
||||
const T small_a { pow(T(10), p10) };
|
||||
const T val = pow(x_val, small_a);
|
||||
|
||||
T val = pow(x_val, small_a);
|
||||
small_a *= 10;
|
||||
|
||||
using std::fabs;
|
||||
|
||||
const T delta { val / small_a_data[k] };
|
||||
const T closeness { fabs(1 - delta) };
|
||||
|
||||
T rel = closeness / local_tol;
|
||||
const T rel = closeness / local_tol;
|
||||
|
||||
unsigned err = rel.template convert_to<unsigned>();
|
||||
|
||||
@@ -222,16 +231,14 @@ void test_small_a_in_default_ops()
|
||||
{
|
||||
max_err = err;
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
|
||||
std::cout << "Max error data having small a: " << max_err << std::endl;
|
||||
|
||||
BOOST_TEST(max_err < 32);
|
||||
BOOST_TEST(max_err < 64U);
|
||||
}
|
||||
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
|
||||
template <class T>
|
||||
void test()
|
||||
@@ -245,7 +252,7 @@ void test()
|
||||
|
||||
const auto& data = local::data_maker<local_test_pow_data_array_type>::get_data();
|
||||
|
||||
unsigned max_err = 0;
|
||||
unsigned max_err = 0U;
|
||||
for (unsigned k = 0; k < data.size(); k++)
|
||||
{
|
||||
T val = pow(T(data[k][0]), T(data[k][1]));
|
||||
@@ -266,9 +273,9 @@ void test()
|
||||
|
||||
std::cout << "Max error from data table was: " << max_err << std::endl;
|
||||
#if defined(BOOST_INTEL) && defined(TEST_FLOAT128)
|
||||
BOOST_TEST(max_err < 40000);
|
||||
BOOST_TEST(max_err < 40000U);
|
||||
#else
|
||||
BOOST_TEST(max_err < 8000);
|
||||
BOOST_TEST(max_err < 8000U);
|
||||
#endif
|
||||
|
||||
//
|
||||
@@ -283,7 +290,7 @@ void test()
|
||||
BOOST_CHECK_EQUAL(pow(T(1), T(2)), 1);
|
||||
BOOST_CHECK_EQUAL(pow(T(1), 2), 1);
|
||||
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
// These were the only ones I checked locally at the moment.
|
||||
|
||||
std::mt19937_64 gen { };
|
||||
@@ -297,7 +304,7 @@ void test()
|
||||
static_cast<float>(1.04L)
|
||||
);
|
||||
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_infinity)
|
||||
{
|
||||
@@ -305,7 +312,7 @@ void test()
|
||||
BOOST_CHECK_EQUAL(pow(T(1.25F), -std::numeric_limits<T>::infinity()), T(0));
|
||||
|
||||
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#if (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
// These were the only ones I checked locally at the moment.
|
||||
|
||||
for (int npow = -8; npow < 8; ++npow)
|
||||
@@ -377,7 +384,7 @@ void test()
|
||||
}
|
||||
}
|
||||
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50))
|
||||
#endif // (defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_BIN_FLOAT) || defined(TEST_CPP_DOUBLE_FLOAT) || defined(TEST_MPF_50) || defined(TEST_FLOAT128))
|
||||
}
|
||||
|
||||
BOOST_IF_CONSTEXPR((!boost::multiprecision::is_interval_number<T>::value) && std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_quiet_NaN)
|
||||
@@ -448,6 +455,8 @@ int main()
|
||||
#endif
|
||||
#ifdef TEST_FLOAT128
|
||||
test<boost::multiprecision::float128>();
|
||||
test_issue722<boost::multiprecision::float128>();
|
||||
test_small_a_in_default_ops<boost::multiprecision::float128>();
|
||||
#endif
|
||||
#ifdef TEST_CPP_BIN_FLOAT
|
||||
test<boost::multiprecision::cpp_bin_float_50>();
|
||||
|
||||
@@ -13,10 +13,9 @@
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <test.hpp>
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include "test.hpp"
|
||||
|
||||
#if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128) && !defined(TEST_CPP_BIN_FLOAT) && !defined(TEST_CPP_DOUBLE_FLOAT)
|
||||
#define TEST_MPF_50
|
||||
@@ -64,6 +63,8 @@
|
||||
#include <boost/multiprecision/cpp_double_fp.hpp>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
|
||||
template <class T>
|
||||
struct has_poor_large_value_support
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user