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;
};
Related
I have a wrapper class for std::string that serves as base class for several others. Instances of the subclasses will be used as keys in std::unordered_set so I need to provide a hash function for them. Since the hash is only dependent on the std::string stored in the base class, I do not want to write a hash function for every subclass but rather use the one from the wrapper class.
This is how I would like to solve the problem:
#include <string>
#include <unordered_set>
class Wrapper {
public:
std::string name;
size_t _hash;
explicit Wrapper(std::string str) : name(str), _hash(std::hash<std::string>()(name)) {}
size_t hash() const { return _hash; }
};
class Derived : public Wrapper {};
namespace std {
template <> struct hash<Wrapper> {
std::size_t operator()(const Wrapper &k) const { return k.hash(); }
};
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
std::size_t operator()(const T &k) const { return k.hash(); }
};
} // namespace std
int main(void) {
std::unordered_set<Wrapper> m1;
std::unordered_set<Derived> m2;
}
This does not compile of course, since T cannot be deduced. Clang says:
20:30: error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
20:20: note: non-deducible template parameter 'T'
And g++ says:
hash_subclass.cpp:21:30: error: template parameters not deducible in partial specialization:
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hash_subclass.cpp:21:30: note: 'T'
I have found this solution, but I would like to avoid using a macro. Also, this goes against what I expect from inheritance.
Is there a solution for this? Can a subclass inherit its base class' specialization of std::hash?
Also, I'm not 100% sure about my use of std::enable_if and std::is_base_of. Could you tell me whether this would work assuming T could be deduced?
IRC, the problem with std::enable_if is that it does not work for classes with a single template parameter. Consequently, you cannot specialize std::hash by using std::enable_if.
However, you can make your own hasher as follows:
template <typename T, typename Enable = std::enable_if_t<std::is_base_of_v<Wrapper, T>>>
struct WrapperHasher {
std::size_t operator()(const T& k) const { return k.hash(); }
};
And then use it as a second template argument of std::unordered_set:
std::unordered_set<Wrapper, WrapperHasher<Wrapper>> m1;
std::unordered_set<Derived, WrapperHasher<Derived>> m2;
But in your case, you can define a wrapper much more simply as:
struct WrapperHasher {
std::size_t operator()(const Wrapper& k) const { return k.hash(); }
};
And then write:
std::unordered_set<Wrapper, WrapperHasher> m1;
std::unordered_set<Derived, WrapperHasher> m2;
I am trying to inherit the std::vector class template into my membvec class template as public. And I want to use it as e.g. say membvec<float> mymemb(10) with the intention of creating my membvec variable mymemb containing 10 elements.
But I can't figure out how to write the templatised declaration of the public inheritance. What I am doing is the following, but all in vain.
template <typename T, template <typename T> class std::vector = std::vector<T>>
//error above: expected '>' before '::' token
class membvec: public std::vector<T>
{
const membvec<T> operator-() const; // sorry the previous version was a typo
//error above: wrong number of template arguments (1, should be 2)
...
};
I think you're looking for something like the below, but seriously don't do it. If you ever pass your class as its parent std::vector, there is no virtual interface to allow your class to provide any benefit whatsoever. And if you don't need to substitute for a std::vector then there's no need to inherit from it. Prefer free function algorithms or containing the std::vector as a member in your class instead.
#include <vector>
template <typename T>
class membvec: public std::vector<T>
{
// Don't need <T> in class scope, must return by value.
membvec operator+() const;
};
int main()
{
membvec<int> foo;
}
Perhaps you want something like this:
#include <vector>
template <typename T, template <typename T, class Allocator> class Vec = std::vector>
class membvec: public Vec<T, std::allocator<T>>
{
public:
// This is the signature in your question, but it's questionable.
const membvec<T, Vec> &operator+(int x) const
{
// You obviously want to change this.
return *this;
}
};
You can then use it regularly:
int main()
{
membvec<char> foo;
foo + 3;
}
Is there any way to get a recursive template type? I have a container for which I want to specify an underlying storage strategy. The inner template must however use the outer template's type, so it causes a loop in the type definition -- which isn't possible to specify.
About what I want:
template<typename C>
struct inner {
C * object[16];
};
template<typename T, typename Inner>
struct container {
T value;
Inner<container> holder;
};
C++11 solutions are fine (though I'm still on gcc 4.6.3).
You need to tell the compiler that Inner is a templated class:
template<typename T, template<typename> class Inner>
struct container {
T value;
Inner<container> holder;
};
I'm not sure why you're adding the Inner type template parameter, since you're defining holder to be a type based on Container and inner, both of which are available at the point you're declaring holder.
Are you planning on using any type other than struct inner as a template param to Container? If not, the following simplified code compiled and ran for me in VS2010 :
#include <vector>
#include <stdio.h>
template <typename C>
struct inner{
C * objects[16];
bool hasobj;
inner():hasobj(false){}
};
template <typename T>
class Container {
inner<Container> holder;
T value;
public:
Container(const T& valueP){
value = valueP;
}
void AddChild(Container* rhs){
holder.objects[0] = rhs; //Always using first location, just for example
holder.hasobj = true;
}
void PrintStuff()const{
if(holder.hasobj){
holder.objects[0]->PrintStuff();
}
printf("VAL IS %d\n", value);
}
};
int main(){
Container<int> c(10);
Container<int> c1(20);
c1.AddChild(&c);
c1.PrintStuff();
}
Basically, this is assuming that the container is always defining holder in terms of inner, which helps get rid of the extra template parameter, when defining Container. Hope this helps :)
arun
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 need a template like this, which work perfectly
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
then i want to specialize the above template for std::string so i came up with
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
which doesnt't work, and throws an error. I would like to make the second example work and then IF possible i would like to add some code in the template to check if a std::vector/std::deque/std::list was used, to do something differently in each case.
So i used templates because 99% of the code is the same for both vectors and deques etc.
To specialize:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
To specialize for deque:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
Have you tried a template typename parameter? The syntax is a bit weird because it emulates the syntax used to declare such a container. There's a good InformIT article explaining this in more detail.
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
Notice that you also should declare the argument as a reference!
By the way: this comment
//check type of container
is a dead giveaway that you're doing something wrong. You do not want to check the type of the container. User more sophisticated overloading instead, as shown in sep's answer.
If I am understanding your problem correctly you have an algorithm that will work for STL containers vector, deque etc but are trying to write a template specialisation for string. If this is the case then you can write the generalised templated method that you defined in your question:-
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
Then for your string specialisation you declare:-
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
For any other specialisation just change the type declaration for myCont. If you really need to do this for the vector and deque containers then make the template parameter the parameter for the type in that container rather than the container itself as Sep suggested.
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
It's worth trying to avoid this by making your first implementation work with all STL containers to make your life easier, then you only need the specialisation for the string class. Even consider converting your string to a vector to avoid the specialisation all together.
On a side note, I've changed the container parameter to a const reference, I assume this is what you want, as you declare the object const anyway, this way you avoid a copy.
The answers so far seem helpful, but I think I'd use a different construct. I expect all containers to define value_type, just like the STL containers do. Therefore, I can write
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
In general, it's easier to act on a parameter that you've extracted explicitly.
#sep
'Simple' solution
The answer posted by 'sep' is pretty good, probably good enough for 99% of app developers, but could use some improvement if it's part of a library interface, to repeat:
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
This will work provided the caller isn't using std::vector. If this works well enough for you, to specialize for vector, list, etc, then stop here and just use that.
More complete solution
First, note that you can't partially specialize function templates -- you can create overloads. And if two or more of them match to the same degree, you will get "ambigous overload" errors. So we need to make exactly one match in every case you want to support.
One technique for doing this is using the enable_if technique -- enable_if allows you to selectively take function template overloads out of the possible match list using an obscure language rule... basically, if some boolean expression is false, the overload becomes 'invisible'. Look up SFINAE for more info if you're curious.
Example. This code can be compiled from the command line with MinGW (g++ parameterize.cpp) or VC9 (cl /EHsc parameterize.cpp) without error:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
Output:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
Whether it is a good design or not is left for further discussion. Anyway, you can detect the type of container using partial template specializations. In particular:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}