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.
Related
I write interfaces through concepts for implementation validation.
There are no problems with conventional methods:
// Interface realization
struct Realization
{
int* TestMethod(const std::string& aStr)
{
return (int *) aStr.c_str();
}
};
// Concept
template <typename T>
concept IRealization = std::is_same_v<decltype(&T::TestMethod), int* (T::*)(const std::string&)>;
// and then, for example
void Check()
{
static_assert(IRealization<Realization>)
}
but when I try to write a similar check for a template method:
// Interface realization
struct Realization
{
template <typename T>
int* TemplateMethod(const T& aStr)
{
return (int *) aStr.c_str();
}
};
, I run into a problem of dectype a template method, because I cant write
decltype(&RealizationImpl::TemplateMethod)
(at the time of checking the interface, I do not know the type that will be substituted)
Please tell me, can I somehow get the signature of the template function without type, or otherwise solve my problem? Thanks!
You should not write concepts like this. A concept should never check for something as specific as a member function with an exact signature. A concept should instead say that, given an instance of the type in question, I should be able to do i.memberFunc(...), where ... is the list of parameters.
For example, your "IRealization" concept (please don't prefix concepts with I. Concepts are not interfaces) ought to say "T must have a member function which can be called given a std::string argument and results in something which is convertible to an int." That would look like:
template <typename T>
concept IRealization = requires(T t, std::string str)
{
{ t.TestMethod(str) } -> convertible_to<int>;
};
This allows the user to provide a TestMethod that takes, for example, std::string_view instead of std::string. There's no point in being so incredibly restrictive on the type.
A concept that checks for T having a member function which is callable with some type U would have to be templated on both T and U:
template <typename T, typename U>
concept IRealization = requires(T t, U u)
{
{ t.TestMethod(u) } -> convertible_to<int>;
};
What is the problem with adding another type to the concept?
// Concept
template <typename T, typename U>
concept IRealization = std::is_same_v<decltype(&T::template TestMethod<U>), int* (T::*)(const U&)>;
For instance.
You could even make it prettier by creating a typedef -
template<typename T, typename U>
using FuncT = decltype(&T::template TestMethod<U>);
I need (want) to specialize a method inside a template class, to allow only certain primitive types. (This is not a duplicate question of this)
Well i've got this class :
template<typename TYPE, size_t NB>
class X
{
public:
template<typename arg_type>
X& get(const arg_type var);
}
I would like to specialize arg_type to allow only unsigned integers, something like this :
template<typename TYPE, size_t NB> template<unsigned long> X& X::get(const unsigned long val);
But sure, the above doesn't work, neither on msvc2011 nor on gcc
To be more specific, what i try to do is to write a code based on the templated type above, and write the specialization so that anyone using this class X cannot use this method with something else than what i specialized.
Is that even possible ? and if it is, is it bad to do it so ?
Thanks in advance,
jav974
A specialization is not what you want. Using a specialization you can provide a special way to treat the instantiation of your template method using an unsigned integral type, but nothing prevents the user from instantiating it with another type.
You can achieve this using some SFINAE:
#include <type_traits>
template<typename TYPE, size_t NB>
class X
{
public:
template<typename arg_type>
typename std::enable_if<std::is_unsigned<arg_type>::value, X&>::type // arg_type is unsigned
get(arg_type val)
{
}
};
You could also use static_assert, so that users get a more friendly error message:
template<typename arg_type>
X& get(arg_type val)
{
static_assert(std::is_unsigned<arg_type>::value, "The argument should be unsigned!");
}
If you want the TYPE template parameter to follow the same rules, you could also use static_assert:
template<typename TYPE, size_t NB>
class X
{
public:
static_assert(std::is_unsigned<TYPE>::value, "TYPE should be unsigned!");
};
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.
I want this code to be possible.
template<typename K, typename T, typename Comparer>
class AVLTree
{
...
void foo() {
...
int res = Comparer::compare(key1, key2);
...
}
...
};
Specifically, I want to force Comparer class to have a static int compare(K key1, K key2) function. I was thinking about using derivation, but could not find any ideas that can work with templates.
Thank you.
You can't. But if use the function and the Comparer doesn't have it, your compile will fail and this is more or less what you want to happen. And yes, like others pointed out you want to call static as static.
Did you try doing:
int res = Comparer::compare(key1, key2);
In C++ Static functions can be called in two ways:
object.static_method(); // use dot operator
classname::static_method(); // use scope resolution operator
Michael already mentioned that this will not compile if Comparer doesn't have the required member function.
If however you're more worried about concise error messages, use something like this to detect if the class has a required member function and combine it with something like Boost.StaticAssert:
template<typename K, typename T, typename Comparer>
class AVLTree
{
BOOST_STATIC_ASSERT(HasCompareMethod<Comparer>::has);
//...
};
It would have to be Comparer::Compare, right? (Since you are calling a static function on a type).
Your Comparer class would have to be defined as follows:
template<typename K>
class Comparer
{
public:
static bool Compare(K key, K key)
{
return true;
}
};
I understand it you're looking for a better error message in case the template parameter doesn't fit the requirements of the template body. the language doesn't have an special mechanism for that built in, but people approximate it using libraries. see Boost Concept Check
The loose approach of having a compile time assertion around this is to take the address of Comparer::compare and assign it to a variable declared as int(K, K) *func.
That assignment will work if it's a static function, but will not work if it's a member function.
I am just contributing this, but I would take the approach of using the boost idioms as this is hand-rolled, so to speak.
Here's a more idiomatic and generic approach:
template<typename K, typename T>
class AVLTree
{
...
template <typename Comparer>
void foo(Comparer cmp) {
...
int res = cmp(key1, key2);
...
}
...
};
Comparer should not be a type that defines a static Compare method. It should be a type which can be called with function call syntax. That allows you to use function pointers of function objects, and it allows you to reuse the comparers already defined in the standard library, or in pretty much any other nontrivial C++ application. It allows you to use lambdas when they're added in C++0x.
As for forcing Comparer to behave as expected? The line int res = cmp(key1, key2); already ensures that. If you try to pass a type that can't be called in this way, you get a compile error.
The same was the case in your original code. If you passed a type that didn't have a static Compare method, you'd get a compile error. So your original code already solved the problem.
As already pointed out, you can't force Compare to have a static member compare. If your comparer doesn't implement it, you just get an compiler error.
If you implement AVLTree like this it would be more elegant to declare Comparer as a template template parameter:
template <typename K>
class DefaultComparer
{
public:
static bool compare(K k1, K k2)
{ return k1 == k2; }
};
template <typename K>
class MyComparer : public DefaultComparer<K>
{
public:
static bool compare(K k1, K k2)
{ return k1 <= k2; }
};
template <typename K>
class InvalidComparer
{
public:
static bool bar(K k1, K k2)
{ return k1 != k2; }
// Doesn't implement compare()
};
// Compare is a template template paramenter with default template argument
// DefaultComparer
template <typename K, template <typename K> class Comparer = DefaultComparer>
class AVLTree
{
K k1, k2;
public:
AVLTree() : k1(0), k2(0) { } // ctor
bool foo();
};
// Definiton of AVLTree::foo()
template <typename K, template <typename K> class Comparer>
bool AVLTree<K, Comparer>::foo()
{
return Comparer<K>::compare(k1, k2);
}
int main(int argc, char *argv[])
{
// Without template template parameters you
// would have to use AVLTree<int, DefaultComparer<int> >
AVLTree<int> avltree;
// instead of AVLTree<int, MyCompare<int> >
AVLTree<int, MyComparer> avltree2;
// Calling foo() will generate a compile error.
// But if you never call avltree3.foo() this will compile!
AVLTree<int, InvalidComparer> avltree3;
avltree.foo(); // calls DefaultComparer::compare
avltree2.foo(); // calls MyComparer::compare
avltree3.foo(); // fails to compile
}
see: http://codepad.org/OLhIPjed
I am trying to implement a template class that would be able to tell me if a variable is a class,structure or a basic type.
So far I've come with this:
template< typename T >
class is_class
{
private:
template< typename X >
static char ( &i_class( void(X::*)() ) )[1];
//
template< typename X >
static char ( &i_class( X ) )[2];
public:
static bool const val = sizeof( i_class< T >(0) ) == 1;
};
and ussage:
is_class< int >::val; // false
is_class< some_class_type >::val; // true
The problem is that now I need to write a blank void function in every class that could be used with this code.
Does anyone know a solution to this problem?
is_class is a member of the Boost.Type_Traits library. The implementation is probably similar to what you already have. You would use in in conjunction with enable_if to create the function if appropriate:
template <class T>
typename enable_if_c<boost::is_class<T>::value>::type
foo() { }
Or the equivalent:
template <class T>
typename enable_if<boost::is_class<T>>::type
foo() { }
The function foo is only generated if the type T is of class type.
The return value for the function, if it is generated, is the second parameter (omitted) to the enable_if template (the default is void).
Use boost's type traits.
If it's only asserting during compile time, you could use BOOST_STATIC_ASSERT and Boost.TypeTraits to check if types are suitable. If you want to enable a template for specific types, you may have success using Boost's enable_if.