Template function that only accepts integer type
I have the following code that rounds up any integers type (long, int, short, etc) to the nearest specified bit position. When non-integer type is used, is there anyway to code it such that the compiler will flag a clear error that only integer type works?
Code:
#include <iostream>
#include <ios>
using namespace std;
template <size_t Pos, typename T>
inline T RoundUp2NearestBitPos(T value)
{
const T mask = (1 << Pos) - 1;
return (value + mask) & ~mask;
}
int main()
{
cout << hex << RoundUp2NearestBitPos<4>(0x0f) << endl;
cout << hex << RoundUp2NearestBitPos<4>(0x10) << endl;
cout << hex << RoundUp2NearestBitPos<4>(0x11) << endl;
cout << hex << RoundUp2NearestBitPos<4>(0x1f) << endl;
}
Thanks in advance.
Re: Template function that only accepts integer type
Im sure you could use a typelist of types you want this to work with then check T against the typelist and if not in maybe throw an exception(logic_error perhaps) or silently exit function doing nothing.
Re: Template function that only accepts integer type
Use static assertions and a type traits template. Boost and Loki have better versions, but here's working code that shows how it can be done.
Code:
template <class T>
struct is_int
{
enum {value = 0};
};
template <>
struct is_int<char>
{
enum {value = 1};
};
template <>
struct is_int<signed char>
{
enum {value = 1};
};
template <>
struct is_int<unsigned char>
{
enum {value = 1};
};
template <>
struct is_int<short>
{
enum {value = 1};
};
template <>
struct is_int<unsigned short>
{
enum {value = 1};
};
template <>
struct is_int<int>
{
enum {value = 1};
};
template <>
struct is_int<unsigned int>
{
enum {value = 1};
};
template <>
struct is_int<long>
{
enum {value = 1};
};
template <>
struct is_int<unsigned long>
{
enum {value = 1};
};
//if long long's are supported
template <>
struct is_int<long long>
{
enum {value = 1};
};
template <>
struct is_int<unsigned long long>
{
enum {value = 1};
};
//C-style static assert
// ANSI-conformant compilers will reject 0 sized arrays
// but GCC accepts them. To be safe use an array size
// of -1. All compilers will reject that!
#define STATIC_ASSERT(expr, msg) \
{ \
char STATIC_ASSERTION__##msg[((expr) != 0) ? 1 : -1]; \
(void)STATIC_ASSERTION__##msg[0]; \
}
template <size_t Pos, typename T>
inline T RoundUp2NearestBitPos(T value)
{
STATIC_ASSERT(is_int<T>::value,
T_not_integer_type_in_RoundUp2NearestBitPos);
const T mask = (1 << Pos) - 1;
return (value + mask) & ~mask;
}
Re: Template function that only accepts integer type
You can set up a flag in your template and let the user determine if he is going to input an integer or a non-integer.
Another way might be a list of types like a table, then just search for a match, which will do better than the previous one, I think...
-Monk eL
Re: Template function that only accepts integer type
Kevin's method I believe would do the task well but what if being wrapped up in one template class rather than being scattered is taken into consideration ?
Monk eL
Re: Template function that only accepts integer type
Something that doesn't require as much specialization and maintainance is to make sure you provide a template that can only do integer operations, but have the function call not actually do anything useful (so it will be optimized away). However, this strategy will make it more difficult to find the culprit behind the error.
Here's an example
Code:
template <typename T>
struct integer_only
{
void operator()()
{
union
{
T t; // only PODs can be members of unions
char c;
} dummy;
// avoid "variable not used" warning
(void) dummy;
// try some operations that should only work for integer types
(void) (1<< T(0));
(void) (~ T(0));
}
};
// have to specialize for bool's because << and ~ operators are legal for bools
template<>
struct integer_only<bool>
{
// this will fail at link time because there is no implementation.
void operator()();
};
class NotAnInt
{
double d;
public:
NotAnInt() : d(3.14)
{
}
};
int main(int argc, char* argv[])
{
// these are ok
integer_only<int>()();
integer_only<char>()();
// these will fail
// integer_only<bool>()();
// integer_only<double>()();
// integer_only<NotAnInt>()();
return 0;
}
Re: Template function that only accepts integer type
Quote:
Originally Posted by Monk el
Kevin's method I believe would do the task well but what if being wrapped up in one template class rather than being scattered is taken into consideration ?
Monk eL
The nice thing about type traits and static assertions is that the errors will occur at compile time rather than run time. That's very useful for preventing bugs before they end up in the field. Also, the Boost and Loki libraries already have these two features pre-canned, so the Keun (or whoever wants to implement something like this) only has to type one line, instead of the many I did.
Re: Template function that only accepts integer type
Thank you all.
I was looking for a way to generate error during compile time when an inappropriate type is used. I like to thank Kevin again for his excellent solutions and suggestions. :thumb:
Re: Template function that only accepts integer type
There is a very simple way to ensure that you only have integral types, and that is to perform an operation that is only valid on integers.
There might be a problem with that of the compiler automatically converting float or double to integers. Have you tried passing a float or double to your function to see what happens? It would certainly fail to compile if you passed in a std::string.
Re: Template function that only accepts integer type
Thanks NMTop40.
I am sorry that I wasn't clear in my question. I was thinking along the line where the compiler could be generating customized error, like "only integer type allowed".
Re: Template function that only accepts integer type
You can use #error to do this.
Write function with no body like those above, eg:
Code:
template < typename T >
void verifyInt()
{
#error integer type required
}
then specialise the function for all integral types to not #error. You can put this within your own class scope.
The method I suggested (something that requires an int) could be implemented by creating a class member function that takes int as parameter and attempting to call it, however it would have the effect of converting float to int. You could also write functions that take const int*, const long * etc for all int types, and those would throw a compiler error if you passed a const float * or const double * to them. However the compiler error would not be customised.
Re: Template function that only accepts integer type
Thanks. You are right that we couldn't really customize the error. The nearest to that is to use compile-time assertion. The generated error on longer points to the line where the operator fails, but rather it points directly at the line that performs the check like the following code in Kevin's example.
Code:
struct integer_only
{
...
};
or
STATIC_ASSERT(is_int<T>::value,
T_not_integer_type_in_RoundUp2NearestBitPos);
IMHO, I think compile-time assertion is still a great asset to all programmer as it helps to narrow down the problem much quicker.
Re: Template function that only accepts integer type
BTW, for anyone who is interested. Here's some links on compile-time assertion that I think is helpful.
http://www.jaggersoft.com/pubs/CVu11_3.html
http://www.embedded.com/showArticle....leID=164900888
Re: Template function that only accepts integer type
Using boost concepts:
Code:
#include <cstddef>
#include <cstdlib>
#include <boost/concept_check.hpp>
namespace
{
template<typename T>
T only_works_for_integers(T t)
{
boost::function_requires< boost::IntegerConcept<T> >();
return t;
};
}
int main()
{
only_works_for_integers(12);
only_works_for_integers(12.0); // will fail because 12.0 is double
return EXIT_SUCCESS;
}
Which gives the following compile-time error:
Code:
Compiling...
type_traits2.cpp
c:\Work\boost_1_32_0\boost_1_32_0\boost\concept_check.hpp(153) :
error C2228: left of '.error_type_must_be_an_integer_type' must have class/struct/union type
type is 'double'
c:\Work\boost_1_32_0\boost_1_32_0\boost\concept_check.hpp(151) : while compiling class-template member function 'void boost::IntegerConcept<T>::constraints(void)'
with
[
T=double
]
c:\Work\boost_1_32_0\boost_1_32_0\boost\concept_check.hpp(48) : see reference to class template instantiation 'boost::IntegerConcept<T>' being compiled
with
[
T=double
]
c:\Work\CG\type_traits2\type_traits2\type_traits2.cpp(16) : see reference to function template instantiation 'void boost::function_requires<boost::IntegerConcept<T>>(boost::mpl::identity<boost::IntegerConcept<T>> *)' being compiled
with
[
T=double
]
c:\Work\CG\type_traits2\type_traits2\type_traits2.cpp(26) : see reference to function template instantiation 'T `anonymous-namespace'::only_works_for_integers<double>(T)' being compiled
with
[
T=double
]
Build log was saved at "file://c:\Work\Cg\type_traits2\type_traits2\Debug\BuildLog.htm"
type_traits2 - 1 error(s), 0 warning(s)
Which is pretty neat I think since the code intent is clear, it produces a somewhat readable error message and it points out the point of invocation.
Of course it's possible to create ones own concepts.
Hope this helps
PS. BGL (Boost Graph Library) uses concepts heavily .
Re: Template function that only accepts integer type
Thanks marten_range. I'll take a look at the boost library.
Re: Template function that only accepts integer type
marten_range, which do you think is better to use, boost concept checks or boost::is_integral<>? What would be the advantages of one over the other?
Re: Template function that only accepts integer type
Quote:
Originally Posted by HighCommander4
marten_range, which do you think is better to use, boost concept checks or boost::is_integral<>? What would be the advantages of one over the other?
In the past I have been using BOOST_STATIC_ASSERT and boost type-traits (such as boost::is_intergral<>) to enforce concepts and only recently began using boost concepts library.
BOOST_STATIC_ASSERT worked very well for me but I think boost concept library is a more complete solution.
One advantage of using boost concept library is that the boost community jumped through some rings in order to provide portable and easy to understand compile-time errors when concepts are violated. As the presentation of compile-time errors are not mandated by the standard it's difficult to get consistent concept error reportage across compilers.
Hope this helps
Re: Template function that only accepts integer type
Just to add to what marten said.
In this case, concept checks and type_traits work in exactly the same way (More or less), so the difference is not that great, though concept checks may result in slightly more readable code and error messages (IMO).
The point where concept checks really stand out (Again IMO), is when you for instance use them to limit the types of iterators a template function can take. Just to give you an example: (Code from a Unicode library I'm currently writing)
Code:
template<typename rs_iter, typename wi_iter>
void compose_hangul(rs_iter first, const rs_iter& last, wi_iter out)
{
// Concept checking of template parameters:
function_requires<boost_concepts::ReadableIteratorConcept<rs_iter> >();
function_requires<boost_concepts::SinglePassIteratorConcept<rs_iter> >();
function_requires<boost_concepts::WritableIteratorConcept<wi_iter, code_point_type> >();
function_requires<boost_concepts::IncrementableIteratorConcept<wi_iter> >();
<boring details removed>
}
This function composes the hangul sequence [first, last] and outputs the results through 'out'. By using concepts checks here the user is now unable to for instance pass a std::istream_iterator<int> as 'wi_iter', since that iterator isn't writable. If you tried that, the compiler would give a nice error message (Most of the time anyway) that a Writable iterator is required, instead of spitting a cryptic message from the depths of the library where you eventually write to the thing.
Needless to say, I love these things.. :)
Re: Template function that only accepts integer type
Thanks Wien. That's very helpful.
Re: Template function that only accepts integer type
Kheun,
You are going to like this. It's a way to restrict the compiler from finding a match for a function unless a given condition is true.
Code:
template <bool> struct restrict_to {};
template <> struct restrict_to<true> {typedef void* type};
#define RESTRICT_TO(condition) \
typename restrict_to<condition>::type = 0
template <typename IntType>
IntType Add(IntType x, IntType y, RESTRICT_TO(boost::is_integral<IntType>::value))
{
return x+y;
}
In order for the compiler to match the 3rd argument, it must use the true restrict_to template specialization. If the condition is false, type doesn't exist as so the compiler can't find a valid instantiation for the template function.
The only down side is that an extra parameter is passed into the function. But being a template and that it will usually be inlined, the compiler will normally optimize this away. But in certain circumstances it will not be able to do so.
Anyway, I hope you enjoy this technique -- or at least reading about it. :)
Re: Template function that only accepts integer type
Thanks, Kevin. I'll try it out.