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.