I have a function which looks like this:
template<class T, class E, class U = T> T function(T input1, E input2) {
// implementation here
}
Instead of the above declaration, I want the default for U
to be a macro which takes T
for input. More specifically, I want the default for U
to be boost::multiprecision::cpp_int
if T
is boost::multiprecision::cpp_int
, and I want the default for U
to be an integer with double the precision of T
for fixed precision T
.
I know the second part can be accomplished with:
U = boost::uint_t<2 * std::numeric_limits<T>::digits>::fast
How do I check for T
being a cpp_int
(or any other arbitrary precision integer within std and boost), and put everything together in a macro?
Edit:
I found that testing for arbitrary precision can be done through:
std::numeric_limits<T>::is_bounded
I still do not know how to combine these 2 tests into 1 macro.
CodePudding user response:
One way could be to use boost::multiprecision::cpp_int
if the double size of T
is larger than an int64_t
.
Idea:
#include <boost/multiprecision/cpp_int.hpp>
#include <cstddef>
#include <type_traits>
// type trait to get an int of the requested size
template<size_t S>
struct int_size {
using type = std::conditional_t<S==1, int8_t,
std::conditional_t<S==2, int16_t,
std::conditional_t<S==4, int32_t,
std::conditional_t<S==8, int64_t,
boost::multiprecision::cpp_int>>>>;
};
template<size_t S>
using int_size_t = int_size<S>::type;
Then make U
double the size of T
or boost::multiprecision::cpp_int
if it's larger than an int64_t
:
template<class T, class E, class U = int_size_t<sizeof(T) * 2>>
T function(T input1, E input2) {
// implementation here
}
CodePudding user response:
Defined a custom boost multiprecision int using a macro, and hid the function backends behind another function which checks types. U is void so that the user has the option of customizing it. If T is fixed precision, the function calls the macro, otherwise passes cpp_int as a template argument. The type deduction of the custom boost int is done at compile time and the if statements are probably evaluated at compile time as well.
#include <limits>
#include <type_traits>
#ifndef BOOST_UINT
#define BOOST_UINT(bit_count) boost::multiprecision::number<boost::multiprecision::cpp_int_backend<bit_count, bit_count, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>
#endif
template<class T, class E, class U = void> T function(T input1, E input2) {
if(std::is_same<U, void>::value) {
if(std::numeric_limits<T>::is_bounded) {
return function_backend<T, E, BOOST_UINT(2 * std::numeric_limits<T>::digits)>(input1, input2);
} else {
return function_backend<T, E, cpp_int>(input1, input2);
}
} else {
return function_backend<T, E, U>(input, input2);
}
}
template<class T, class E, class U> T function_backend(T input1, E input2);