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
Related
I'm writing a C++ template that needs two params: typename T, and an arbitrary function that maps T to an unsigned int.
How can I declare and use a template that can do that? I'd like to keep it simple, so that any dumb function can be used.
UPDATE:
Here is an example of what I'd like to do:
template<typename T, function f> // f has signature: unsigned int f(T);
class SortedContainer {
...
}
And, in this file:
unsigned int weight(Package p) { return p.w; }
SortedContainer<Package, &weight> sc;
UPDATE upon writing code
Based on the answers, I tried writing code, but it won't compile. Or rather, the template will compile, but not the test which invokes it.
The template code looks like this:
template<typename T, typename f>
class C {
...f(T)...
...
The invocation code looks like:
struct S {
int operator()(const int n) {
return n; // Dummy test code
}
};
...C<int, S>&...
The error message is:
error: no matching function for call to 'S::S(const int&)'
note: candidates are:
note: S::S()
It seems like it's trying to use S's constructor for some reason, as opposed to using the operator() which I want it to do.
The purpose of the f parameter is that the SortedContainer needs to be able to position T by an integer value. T is not necessarily an integer or even Comparable, so the caller, when instantiating a SortedContainer, needs to pass not only type T, but a function f to transform T to an integer.
The common way of doing this is to accept a general type F for the function. This will allow any kind of function-like object, whether it is a function pointer or a class object with an overloaded operator(). So:
template<class T, class F>
class SortedContainer {
// ...
}
Compare with things like std::map which does exactly this.
The disadvantage of this is that you cannot control what the prototype of the function is. This may or may not be a problem. One way is just to use it as if it was T-to-unsigned int and rely on the fact that the type system will catch any errors at the point of use.
Another way would be to verify the constraint with some kind of type trait. An example:
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
Edit: I wrote a small example to convince myself i got the assert right, might as well post it. Here, using A will compile OK but B will fail the assertion.
#include <type_traits>
template<class T, class F>
class SortedContainer {
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
};
struct A {
unsigned int operator()(double) { return 0; }
};
struct B {
double operator()(double) { return 0; }
};
int main() {
SortedContainer<double, A> a;
SortedContainer<double, B> b;
}
Based on your other edit:
Note that the templated type F only captures the type of the function. You still need an object of this type - the actual function - to call. Again, compare with std::map which first is templated to take a comparator type, and then has a constructor that takes an object of this type. This is true even if you use a normal function - the type will be SortedContainer<T, unsigned int (*)(T)>, but you would somehow need to pass the actual function pointer into the container (probably through the constructor).
Something like this:
template<class T, class F>
class SortedContainer {
public:
SortedContainer(F f = F()): func(f) {}
void foo() {
// ...
func();
// ...
}
private:
F func;
};
struct A {
unsigned int operator()() { return 0; }
};
int main() {
A a;
SortedContainer<double, A> c(a);
c.foo();
}
IMO, you don't require a separate template argument for Function F.
template<typename T> // F not required!
class SortedContainer {
...
};
Choose a good name and use that function by overloading it for various cases. e.g. to_uint()
Since you want to map (i.e. relate) a type to an unsigned int (uint), use following function in global scope:
template<typename T>
uint to_uint (const T& t) {
return t.to_uint(); // Must have `uint to_uint() const` member, else error
}
// Overloads of `to_uint()` for PODs (if needed)
template<typename T> // For all kinds of pointers
uint to_uint (const T* const pT) {
if(pT == nullptr)
<error handling>;
return to_uint(*pT);
}
Scenario: For Sorted_Container<X>, whenever to_uint(x) is invoked, then:
If X is a class, then it must have uint to_uint() const method
Else if X is a POD, then you may have to overload to_uint() for that type
Else, the compiler will generate an error
It's as you said, pretty much:
template< typename T, unsigned int f(T) >
struct SortedContainer;
...
SortedContainer<Package, weight> sc;
if you actually wanted the argument to be a function pointer rather than a function,
template< typename T, unsigned int (*f)(T) >
and similarly if you want the argument to be a function reference.
(naturally, this will only work for dumb functions, not for function objects with an operator() operator of the right signature)
You may use C-style function pointers as #Hurkyl suggests, or std::function which probably can't be template parameters, but I think that idea is wrong.
C++ templates are duck-typed, so STL code in many places (std::unordered_map -> std::hash, std::sort -> std::less) relies on that. I think you should also apply this approach - just ask user to provide specialization for type T:
/* Universal implementation */
template<typename T>
unsigned int sorted_container_weight(T t) { return t; }
template<typename T>
class SortedContainer {
T t;
public:
unsigned int somefunc() {
return sorted_container_weight(t);
}
};
template<>
unsigned int sorted_container_weight<Package>(Package p) { return p.w; }
SortedContainer<Package> sc;
I wrote a template that wraps a std::vector to make sure the vector is always sorted:
template <typename T> class SortedVector{
public:
SortedVector(bool (*comparator)(T,T)=DefaultComparator<T>){
this->comparator = comparator;
}
void insertValue(T newElement){
vect.insert(std::lower_bound(
vect.begin(),vect.end(),newElement,comparator),newElement);
}
private:
std::vector<T> vect;
bool (*comparator)(T,T);
};
I want to be able to use a custom comparators, but in most cases it will be ok to simply use T's < operator. However, I did not find any better way than to use this
template <typename T> bool DefaultComparator(T a,T b){return a<b;}
as the default parameter.
Maybe it is a stupid question... Isn't there a nicer way to get the same without defining my own DefaultComparator?
I cannot use C++11.
There isn't a standard function template to do what you want; but there is a standard function class template, std::less. If you were to use a generic function object, rather than restricting yourself to a function pointer, then it's easy to specify that as a default:
template <typename T, typename Comparator = std::less<T> >
class SortedVector{
public:
SortedVector(Comparator comparator = Comparator()){
this->comparator = comparator;
}
void insertValue(T newElement){
// lower_bound accepts any suitable function object, so no change needed
vect.insert(std::lower_bound(
vect.begin(),vect.end(),newElement,comparator),newElement);
}
private:
std::vector<T> vect;
Comparator comparator;
};
You can use class template std::less<T> as default.
template <typename T, typename C=std::less<T>>
class SortedVector
{
public:
SortedVector(C cmp=C()) : comparator(cmp)
{
}
void insertValue(T newElement){
vect.insert(std::lower_bound(
vect.begin(),vect.end(),newElement,comparator),newElement);
}
private:
std::vector<T> vect;
C comparator;
};
I already know that you can enable (or not) a class's method using std::enable_if
for exemple:
template<size_t D, size_t E>
class Field
{
...
size_t offset(const std::array<float,D>& p) const
{
...
}
template<typename TT = size_t>
typename std::enable_if<D!=E, TT>::type
offset(const std::array<float,E>& p) const
{
return offset(_projection(p));
}
...
};
This helps not being able to call function that are invalid in a specific case as well as removing overloading errors ... which, to me, is very nice !
I'd like to go further and make some of my class's members being present only if the are needed. That way I would get an error if I try to use an objected which would have otherwise not been initiated
I tried to do
template<size_t D, size_t E>
class Field
{
...
template<typename TT = projectionFunc>
typename std::enable_if<D!=E, TT>::type _projection;
}
But the compiler tells me :
erreur: data member ‘_projection’ cannot be a member template
Is there any way to achieve what I want ?
Hold the data members in a separate class that you can then specialize as needed.
template<size_t D, size_t E>
class Field {
template<size_t, size_t> struct Field_Members {
int _projection;
};
template<size_t V> struct Field_Members<V, V> { };
Field_Members<D, E> m;
};
and then use m._projection etc.
Field_Members doesn't have to be a nested class template; you can move it outside if desired. It is also possible to have Field inherit from it, but then it'd be a dependent base, and you'd have to write this->_projection, so it doesn't save much typing.
AFAIK, this is not possible with a simple SFINAE inside the class template. You can, of course, have the type of the member dependent on a compile-time condition, i.e. via std::conditional, but not eliminate the member entirely.
What you can do, of course, is use another class template, such as
template<bool Condition, typename T> struct Has { T value; };
template<typename T> struct Has<false,T> {};
and declare a member (or base) of this type and access the object via Has<>::value:
typename<bool Condition>
class foo
{
Has<Condition, double> x; // use x.value (only if Condition==true)
};
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.
Consider the following contrived example of a templated array definition:
template <typename t, unsigned int n> class TBase
{
protected:
t m_Data[n];
//...
};
template <typename t, unsigned int n> class TDerived : public TBase<t, n>
{
TDerived()
{
}
};
I can specialize this type to provide a non-default constructor for an array of length 2 as follows:
template <typename t> class TDerived<t, 2> : public TBase<t, 2>
{
public:
TDerived(const t& x0, const t& x1)
{
m_Data[0] = x0;
m_Data[1] = x1;
}
};
int main()
{
TDerived<float, 2> Array2D_A(2.0f, 3.0f); //uses specialised constructor
TDerived<float, 3> Array3D_A; //uses default constructor
return 0;
}
Is there some other way I can create a class that has different constructor options constrained against template parameters at compile-time without the requirement for a complete class specialisation for each variation?
In other words, is there some way I can have specialised constructors in the TBase class without the need for the intermediary step of creating TDerived whilst preserving the functionality of TBase?
I think deriving your class from a base class is not relevant to the question here, that's a mere implementation detail. What you really seem to be after is if there's a way to partially specialize member functions, like the constructor. Do you want something like this?
template <typename T, int N> class Foo
{
Foo(); // general
template <typename U> Foo<U, 2>(); // specialized, NOT REAL CODE
};
This doesn't work. You always have to specialize the entire class. The reason is simple: You have to know the full type of the class first before you even know which member functions exist. Consider the following simple situation:
template <typename T> class Bar
{
void somefunction(const T&);
};
template <> class Bar<int>
{
double baz(char, int);
};
Now Bar<T>::somefunction() depends on T, but the function only exists when T is not int, because Bar<int> is an entirely different class.
Or consider even another specialization template <> class Bar<double> : public Zip {}; -- even the polymorphic nature of a class can be entirely different in a specialization!
So the only way you can provide specializations new declarations of members, including constructors, is by specializing the entire class. (You can specialize the definition of existing functions, see #Alf's answer.)
There are basically two options I see for this:
Use a variadic function for construction (ie. "..." notation), you can use the value n inside that function to get your arguments from the stack. However, the compiler will not check at compile time if the user provides the correct number of arguments.
Use some serious template magic to allow a call chaning initialization, that would look like this: vector(2.0f)(3.0f). You can actually build something that at least ensures the user does not provide too many arguments here. However tha mechanism is a little more involved, I can assemble an example if you want.
You can always specialize a member, e.g.
#include <stdio.h>
template< class Type >
struct Foo
{
void bar() const
{ printf( "Single's bar.\n" ); }
};
template<>
void Foo< double >::bar() const
{ printf( "double's bar.\n" ); }
int main()
{
Foo<int>().bar();
Foo<double>().bar();
}
But you want effectively different signatures, so it's not directly a case of specializing a member.
One way forward is then to declare a constructor with a single argument, of a type dependent on the template parameters.
Then you can specialize that, as you want.
Cheers & hth.,
Since constructor is a function, you need to fully specialize the containing class to address your specific problem. No way out.
However, functions cannot be partially specialized (in all compilers). So suppose if you know that you need n = 2 when t = int or double then following is one alternative.
template<>
TDerived<int,2>::TDerived()
{
//...
}
template<>
TDerived<double,2>::TDerived()
{
//...
}
and so on.
[Note: If you use MSVC, then I think it supports partial specialization; in that case you can try:
template<typename t>
TDerived<t,2>::TDerived()
{
//...
}
though, I am not sure enough for that.]
You could give the most common definitions in the non-specialized class and static_assert (BOOST_STATIC_ASSERT for non C++0x) on the array length. This could be considered a hack but is a simple solution to your problem and safe.
template<typename T, unsigned int n>
struct Foo {
Foo(const T& x) { static_assert(n == 1, "Mooh!"); }
Foo(const T& x1, const T& x2) { static_assert(n == 2, "Mooh!"); }
};
The "evil" way would be variadic arguments.
template<typename T, unsigned int n>
struct Foo {
Foo(...) {
va_list ap;
va_start(ap, n);
for(int j=0; j < n; ++j)
bork[j] = va_arg(ap, T);
va_end(ap);
}
};
Then there is also C++0x and the good old make_something trick which is more difficult then one would think.
template<typename... T, unsigned int n>
Foo<T, n> make_foo(T&&...) {
// figure out the common_type of the argument list
// to our Foo object with setters or as a friend straight to the internals
Foo< std::common_type< T... >::type, sizeof(T) > foo;
// recursive magic to pick the list apart and assign
// ...
return foo;
}