safe integer conversion in c++ - c++

I want to create a simple integer range checker and converter using c++ templates.
The code looks like this:
// D is the "destination" type and S the "source" type
template <class D, class S>
inline D SafeConvert( S value );
template <class S>
inline int SafeConvert<int>( S value ) {
ASSERT( value >= S(INT_MIN) && value <= S(INT_MAX) );
return int(value);
} /// error C2768: 'SafeConvert' : illegal use of explicit template arguments
template <class S>
inline size_t SafeConvert<size_t>( S value ) {
ASSERT( value >= S(0) && value <= S(size_t(-1)) );
return size_t(value);
} /// error C2768: 'SafeConvert' : illegal use of explicit template arguments
// ...
void test() {
size_t v = INT_MAX+1;
int iv = SafeConvert<int>(v);
}
However I have the following come compilation errors:
error C2768: 'SafeConvert' : illegal use of explicit template arguments
My question is how to tell the compiler that I want to specialize only the D class ?
Thanks.

You can't partially specialize function templates. You need to mimic it with a class wrapper or use standard function overloading. An example of mimicing:
template <typename T1, typename T2>
struct processor;
template < typename T1, typename T2 >
T1 fun(T2 t2) { return processor<T1,T2>::apply(t2); }
template < typename T2 >
struct processor<int,T2>
{
static int apply(T2 t2) { .... }
};
...etc...

It's going to be a bother, and a hell to maintain.
Normally I would advise using the numeric_limits:
template <class D, class S>
D SafeConvert(S value)
{
ASSERT(value >= std::numeric_limits<D>::min()
&& value <= std::numeric_limits<D>::max());
return static_cast<D>(value);
}
However there is a warning emitted by the compiler whenever you compare a signed integer with an unsigned one... (never really understood this by the way)
So, instead of reinventing the wheel, I shall advise the use of Boost.NumericConversion and notably: boost::numeric_cast<>.
It's guaranteed to be performance free when the check is not required (ie the destination type is bigger than the source type) and otherwise perform the necessary checks.

Write a structure SafeConverter<T, S> that is used by SafeConvert. Better than partial specialization would be using std::numeric_limits, or even boost::numeric_cast, which already implements range checking in a more sophisticated way.
The latter could be implemented as follows:
template<typename T, typename S>
struct numeric_converter {
static T convert(const S& val);
}
template<typename T, typename S>
T numeric_cast(const S& val) {
typedef numeric_converter<T, S> converter;
return converter::convert(val);
}

Just write SafeConvert<size_t, S> instead of SafeConvert<size_t>, I think, to specialise only the second parameter. Noah Roberts is correct, too, on the point of partial specialisation of functions versus types.

Related

c++ check if a type is a fixed char array in a template

I need to do some special handling of string types in a template I'm writing, but I'm running into a problem with fixed size char arrays. I'm aware I can write code like mentioned in this answer to create a wrapper: Const char array with template argument size vs. char pointer
But I was wondering if there was a way to test if this is a const char array from within a templated function with a static assert, something like this:
template<typename T>
void f(T& val /* a handful of other params */ )
{
static_assert(
std::is_same_v < T, const char* > ||
std::is_same_v < T, char[N] > || // how do I get/discard N here?
std::is_same_v < T, std::string >
, "Unsupported type" );
}
My motivation for this is to avoid having a ton of function signatures for all valid type combinations, while still ensuring only valid types are allowed. Writing all those type declarations and definitions is a nightmare for a few reasons. But as strings can come in various fixed size arrays, I'm unsure how to check them without a wrapper to peel off the length data, but then I am back to writing a ton of wrappers which is exactly what I'm trying to avoid (if there is some way to write a simple reusable test using a single wrapper that would be ok, but I haven't been able to figure one out). And for each string like this, if I was to manually add a wrapper for each time a string param appears in a param list, it will obviously double the number of declarations and definitions I need to write, creating a lot of redundant code. So is there any way to determine if a type is a fixed array type, and only then extract the pointer without the length so I can check it against a const char*? Or someway to ignore the array length and just check if it's a char type array in my assert?
You cannot determine whether a T is an array like that directly, but the standard library provides traits for determining whether a given type is an array already: std::is_array.
Though std::is_array also accepts char[], which may be undesirable. In that case if you have access to C++20, you can use std::is_bounded_array. If you don't have access to C++20, implementing one is rather trivial, or if you want to only check for char[N]:
template <class> struct is_bounded_char_array : std::false_type {};
template <size_t N>
struct is_bounded_char_array<char[N]> : std::true_type {};
template <class> struct is_bounded_array : std::false_type {};
template <class T, size_t N>
struct is_bounded_array<T[N]> : std::true_type {};
static_assert(!is_bounded_array<char>{});
static_assert(!is_bounded_array<char[]>{});
static_assert(is_bounded_array<char[42]>{});
Then, instead of std::is_same_v < T, char[N] >, you can say is_bounded_array<T>.
To get a const char* from any of your types, you could use std::string_view(t).data() instead of handling each case yourself.
It is not possible due to type decay; Result type of T (from function foo) is char*. You can figure it out via my example, just try to compile it:
#include <type_traits>
template<typename T>
struct is_inbuild_array final : std::false_type{};
template<typename T, std::size_t N>
struct is_inbuild_array<T[N]> final : std::true_type{};
template<typename T>
void f(T val)
{
static_assert(
is_inbuild_array<T>::value,
"Unsupported type"
);
}
int main()
{
char array [] = "Test";
f(array);
}
But you can modify your function like this(use universal reference):
template<typename T>
void f(T&& val)
{
static_assert(
is_inbuild_array<std::remove_reference_t<T>>::value,
"Unsupported type"
);
}
And it works well
I wound up doing this to implement the detection based off the other answers here:
#include <type_traits>
template < typename Desired, typename Actual > struct is_bounded_type_array : std::false_type {};
template < typename Desired, typename Actual, std::size_t N >
struct is_bounded_type_array < Desired, Actual[N] > : std::conditional_t < std::is_same_v < Actual, Desired >, std::true_type, std::false_type > {};
template < typename Desired, typename Actual >
inline constexpr bool is_bounded_type_array_v = is_bounded_type_array < Desired, Actual > ::value;
Then I can use it like this in my functions:
template<typename T>
void test(const T& value)
{
std::cout << is_bounded_type_array_v<char, T> << std::endl;
// or
static_assert(is_bounded_type_array_v<char, T>, "Must be bounded array of type char");
}

SFINAE with template pack: disabling member if no template arguments

I would like to define a class, with an optional template parameter such that:
if the parameter exists and it is an enum class, defines an
operator()
the class can be istantiated without the additional template
parameter (in which case operator() does not exists)
The goal is to allow access to an array element through an optional enum class.
Code:
#include <type_traits>
template <int N, typename... T>
class data {
int x[N];
template <typename T0, typename... T1>
struct enum_wrapper {
typedef T0 type;
};
public:
template <bool activate = (sizeof...(T) > 0)>
std::enable_if_t<activate, int>&
operator()(const typename enum_wrapper<T...>::type& e)
{ return x[static_cast<std::size_t>(e)]; }
};
int main()
{
data<3> a;
return 0;
}
The purpose of enum_wrapper is to single out the first parameter in the pack typename... T.
The code compiled with g++ -std=c++14 gives an error
error: wrong number of template arguments (0, should be at least 1)
on the definition of operator(). This is because enum_wrapper<T...>::type is not defined when data is istantiated with a single parameter <3>.
However, the template parameter bool activate in the definition of operator() and its return type std::enable_if_t<activate, int> is meant to prevent the instantation of operator() when the parameter pack typename... T is empty.
Why the definition of operator() is not simply discarded under SFINAE?
Also, I would like to further eliminate operator() when enum_wrapper::type is not an enum class, using std::is_enum.
Where a condition like
std::enable_if<std::is_enum_v<(enum_wrapper<T...>::type)>>
should be inserted to make SFINAE work?
The issue is that the argument type to operator() doesn't depend on the template arguments (to operator())
You can make it depend via an indirection that specifies a new parameter pack that must be the same as the class' (unfortunately we cannot default a parameter pack otherwise we would)
template <bool activate = (sizeof...(T) > 0), typename... U>
std::enable_if_t<activate && std::conjunction_v<std::is_same<T, U>...>, int>&
operator()(const typename enum_wrapper<U...>::type& e)
{ return x[static_cast<std::size_t>(e)]; }
Demo
I suppose I have some concerns as to how'd you actually plan on calling operator(), since enum_wrapper is private within the class. I think what you're really interested in is receiving a type that is the same as enum_wrapper<T...>::type. What is easiest here is to simply make a specialization for enum_wrapper for an empty T..., and then disable operator() for it:
template<class...>
struct enum_wrapper{using type = int;};
template <typename T0, typename... T1>
struct enum_wrapper<T0, T1...> {
typedef T0 type;
};
//...
template <bool activate = (sizeof...(T) > 0)>
std::enable_if_t<activate, int>&
operator()(const typename enum_wrapper<T...>::type& e)
{ return x[static_cast<std::size_t>(e)]; }
And then we could call it like so:
data<3> a; // no operator()
data<3, int> b; // operator() viable
b.x[0] = 1;
b.x[1] = 3;
b.x[2] = 5;
std::cout << b(1) << std::endl; // print '3'
Better Demo
(I made member x public for testing purposes)
In the end, it may be easier to simply move the condition that your argument to operator() is of the type enum_wrapper<T...>::type into a static_assert within the function that is protected by your bool activate:
template <class U, bool activate = (sizeof...(T) > 0)>
std::enable_if_t<activate, int>&
operator()(const U& e)
{
static_assert(std::is_same_v<U, typename enum_wrapper<T...>::type>, L"argument type to operator() is incorrect");
return x[static_cast<std::size_t>(e)];
}
You can call it like before, and there's still no operator() defined for a. If you tried to call b(2.0), though, you'd trigger the static assertion.
Best Demo

Template matching two (seemingly) unrelated types

I have a scoped enum:
enum class E
{ A, B, C };
Now I want to have a function, which accepts a value of that scoped int OR an int itself.
It should be something like:
template <typename T, std::enable_if_t<std::is_same<T, enum E **OR** int>::value, int> = 0 >
void foo(T value);
But I don't know how to deal with the concept of OR in C++ templates. I know std::is_convertible, however I don't even know, if I could use it here, because you can only static_cast scoped enums to int.
But anyway I don't want to accept any type that is convertible to int but only types of that single enum or int.
Overload seems the simplest:
void foo(int value);
void foo(E value) { foo(static_cast<int>(value); } // Or specific code
template <typename T> void foo(T) = delete; // To forbid type convertible to int
else you can use SFINAE
template <typename T>
std::enable_if_t<std::is_same<int, T>::value || std::is_same<E, T>::value>
foo(T value);
Because std::is_same<...>::value is a boolean, you can simply use || operator with 2 std::is_same<...>::value :
template <typename T, std::enable_if_t<std::is_same<T, enum E>::value || std::is_same<T, int>::value, int> = 0 >
void foo(T value);
std::is_same instantiations define a constexpr implicit bool conversion, so you can instantiate them and perform logical OR with ||. In C++17, you will also be able to use std::disjunction to similar effect, although this will likely compile slower for only two type traits. Example of both:
#include <type_traits>
enum class E
{ A, B, C };
template <typename T, std::enable_if_t<
std::is_same<T, E>{} || std::is_same<T, int>{},
int> = 0>
void foo(T){
}
//in C++17, you can also do this:
template <typename T, std::enable_if_t<
std::disjunction<std::is_same<T, E>, std::is_same<T, int>>{},
int> = 0>
void bar(T){
}
int main() {
foo(E::A);
foo(0);
//foo('A'); fails
bar(E::A);
bar(0);
//bar('A'); fails
return 0;
}
std::disjunction is the logical OR template you were wondering about (although I recommend using || with std::is_same for your case). Interestingly, std::disjunction even performs logical short-circuiting of template instantiations, just like the humble old || operator does in a runtime context. I believe recent versions of libc++ are already shipping with std::disjunction. If your <type_traits> implementation doesn't have it yet, the example implementation at cppreference works just fine for me. If you get the chance, you should see how it works. It's rather clever!

Using non-type template argument during partial specialization

Consider the following structs:
//Implementations provided elsewhere
struct A { A(int i, double d, std::string s); /* ... */ };
struct B { B(double d1, double d2); /* ... */ };
I have two conversion classes whose template signatures look like:
TupleAs< A, int, double, std::string > via1 { ... };
ArrayAs< B, double, 2 > via2 { ... };
Predictably, TupleAs converts a triplet of int,double, and std::string values into an object of type A. Similarly, ArrayAs converts a pair of two double values into an object of type B. (And yes, there are reasons why I cannot call the A and B constructors directly.)
Improving the syntax
I would like to change the syntax so I can do the following:
TupleAs< A(int,double,std::string) > via1 { ... };
ArrayAs< B(double,2) > via2 { ... };
which, I think, is more descriptive of a conversion process. The TupleAs template declaration and corresponding partial specialization would look like this:
template <typename T> struct TupleAs;
template <typename T, typename ... Args>
struct TupleAs<T(Args...)> { ... };
Compiler errors
However, if I try to do something similar with the ArrayAs version:
template <typename T> struct ArrayAs;
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
I get the following errors in clang (3.6) when trying to instantiate it (ArrayAs< B(double,2)> test;):
typeAs.cpp:14:22: error: unknown type name 'N'
struct ArrayAs<T(U,N)>{
^
typeAs.cpp:14:10: warning: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
struct ArrayAs<T(U,N)>{
^~~~~~~~~~~~~~~
typeAs.cpp:13:45: note: non-deducible template parameter 'N'
template<typename T, typename U, unsigned N>
^
The gcc error diagnostic is a little different, but I won't post it here.
I admit that my templating skills should be better than they are, and I also concede that an analogous std::function<B(double,2)> declaration clearly is nonsense. But can someone tell me why the particular syntax I'm trying to achieve is not allowed? I looked through the C++14 standard and had trouble finding the relevant portion, and I'm having trouble interpreting the clang diagnostic message.
When you specialize TupleAs:
template <typename T, typename ... Args>
struct TupleAs<T(Args...)>
You are basically overloading the notation for a function. You are specializing on a function that takes Args... and returns a T. That is a type. You may not be using that function as a function, or really ever think about it as being a type, but that is what it is.
On the other hand, here:
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
There is no such thing as a function that takes N. It could take unsigned, but it can't take a value. There is just no such reasonable thing. From your example, B(double, 2) simply does not make sense. At best, you could write something that would allow:
template <unsigned N> using size_ = std::integral_constant<size_t, N>;
ArrayAs< B(double,size_<2>) >
Or even:
ArrayAs< B(std::array<double, 2>) >
since now we're back to using types everywhere. Whether you prefer that or not is personal preference.
The key here is that types are first-class citizens when it comes to all things template metaprogramming, and values should be avoided where possible.
template <typename T> struct ArrayAs;
template <typename T, typename U, std::size_t N>
struct ArrayAs<T(std::array<U,N>)> { ... };
works, as would:
template<class T>
struct to_array;
template<class T, size_t N>
struct to_array< T[N] > { using type = std::array<T, N>; };
template<class T>
using arr = typename to_array<T>::type;
then:
ArrayAs< Bob( arr<int[3]> ) > some_var;
live example.
Sadly, directly using ArrayAs< Bob( int[3] ) > doesn't work due to how arrays in function types decay to pointers.

Getting type from template value, C++

I have the following method in which I'm using boost::variant. I try to get the value, based on type T. If boost::get<T> fails I want to handle that in a special way if T is an int or unsigned int. Is there any way to know if T is an int or unsigned int?
I don't think I can use template specialization in this case, can I?
EDIT: Also, I don't yet have access to C++11 (soon I hope)
template < typename T, typename C, void (C::*setterFcn)(const T&) >
void binder( const Variant& value_var, C* c )
{
const T* typeData = boost::get<T>(&value_var);
if ( NULL == typeData )
{
// Need to check for int or unsigned int here somehow
}
(((C*) c)->*(setterFcn))(*typeData);
}
In C++11 you can use std::is_same and in C++03 you can do something like this:
template <typename T1, typename T2>
class is_same
{
public:
static bool const value = false;
};
template <typename T>
class is_same<T, T>
{
public:
static bool const value = true;
};
and use it exactly as C++11 standard version.
You could also use is_same() on boost or on C++11.
http://www.boost.org/doc/libs/1_51_0/libs/type_traits/doc/html/boost_typetraits/reference/is_same.html
http://en.cppreference.com/w/cpp/types/is_same
The easiest way is probably to just delegate to overloaded functions or function templates: You specify the general handling, possibly doing nothing, in one function and the specialized handling either in two separate functions (if the extra handling is trivial) or in an enable_ifed function with the condition checking for int or unsigned int.