The project I'm working on has some pretty nasty collection classes that I feel could use a redesign. I'd really like to make a collection template class that takes model instances and provides a way to call type-specific functions of each child in the collection. For example, something like:
MyCollection<Student> BiologyStudents();
// [Fill the collection]
BiologyStudents.EnrollInClass(ClassList::Biology);
BiologyStudents.Commit();
The idea is that I could easily enroll all students in a class using my collection, then commit those changes to a database. My problem is in how to expose that EnrollInClass() function which belongs to the children Student objects? If my collection contains objects of a different type than Student, I would like those functions to be exposed from the collection. The only way I can think to do that with my semi-limited C++ knowledge would be to make a function that takes a parameter which references a function I know is in the containing child class. This wouldn't provide compilation errors if you call the wrong function or provide the wrong parameters, so I'd like a way to utilize the compiler to provide these checks.
Is this possible? If so, how? As a warning, I'm used to generic programming in Java/C#, so my impression of C++ templates might be a bit off.
One way would be to use a method pointer:
template <typename T>
struct MyCollection {
template <typename U>
void ForEach(void (T::*func)(U),U param)
{
// for each item loop goes here
(item.*func)(param);
}
};
MyCollection<Student> BiologyStudents;
// [Fill the collection]
BiologyStudents.ForEach(&Student::EnrollInClass,ClassList::Biology);
You would have to provide different versions for different numbers of parameters.
With C++11, you can do this:
template <typename T>
struct MyCollection {
void ForEach(std::function<void (T &)> func)
{
// for each item loop goes here
func(item);
}
};
MyCollection<Student> BiologyStudents;
// [Fill the collection]
BiologyStudents.ForEach([](Student &s){s.EnrollInClass(ClassList::Biology);});
Which would not require making different versions of ForEach for different numbers of parameters.
Related
I have stumbled many times on classes defined like
class PureVirtualClass
{
virtual int foo() = 0;
virtual bool bar() = 0;
}
template <class T> class ImplClass : public virtual PureVirtualClass
{
virtual ~ImplClass(){};
int foo() { return 42;}
bool bar() { return true;}
//several other method having nothing to do with T
}
This "design" appears so often I want to think the original developer knew what he was doing by defining ImplClass as template class but without any reference to the template argument T anywhere. My own c++ template knowledge is kinda limited.
Is there a benefit to this or is it just a confused programmer?
There can be a benefit for classes being templated but not depending on the argument. Most often you see such things to define (empty) tag-structures for template metaprogramming:
template <class X>
struct some_tag {};
The benefit of classes like yours in general is that while you have the same functionality in each class, they are different classes and you can't copy one into the other, i.e. an object of type ImplClass<int> is not compatible with another object of type ImplCalss<float>.
There are many useful cases of the idea mentioned by Arne. For instance, looking at Very basic tuple implementation, this is how a single tuple element is defined:
template <size_t N, typename T>
class TupleElem
{
T elem;
public:
T& get() { return elem; }
const T& get() const { return elem; }
};
It is templated on N, without depending on it. Why? Because the tuple implementation
template <size_t... N, typename... T>
class TupleImpl <sizes <N...>, T...> : TupleElem <N, T>...
{
//..
};
derives multiple such elements, each with a unique N, serving as an identifier. Without it, TupleImpl would be deriving the same class twice, had two element types been identical within parameter pack T.... Neither random access to elements would work in this case (via an explicit call of function get() of the appropriate TupleElem base class, which would be ambiguous), nor empty base optimization (via specializing TupleElem for empty types T to not have a data member of type T).
This is a real use case, and exactly how std::tuple is implemented by clang. Of course, a class like TupleElem would be a hidden implementation detail, and not part of the interface. For instance, gcc follows an entirely different recursive class design.
In general, you will need to study the context where classes are used to understand the intent of the designer.
maybe that developer simply is too lazy to split the classes into .h and .cpp files?
Without using templates, linker errors would occur if the classes are used in multiple compilations units. When using templates, the linker usually discards duplicate instantiations of a template at link time (or handles the problem in a different way).
While this may be an answer to "why did the developer do this", I would not recommend this if the question was "when should I introduce template arguments which are never used" (see the other answers for this). Even though it is annoying to split code into .h and .cpp (especially when used to languages like Java or C#), it's the usual C++ way. And it is definitely easier to read/understand than using templates only for this purpose. Also, it makes the use of the classes less readable.
I have a tricky question about C++(11) template classes and their instantiation with types determined at runtime:
Following scenario:
The user defines the type of a template class using a config file (ROS parameters). This determines only the type of the template class, not the further logic:
Class definition:
template<typename T>
class MyClass {
//[...]
}
Exemplary code:
/* [Read parameter and write result to bool use_int] */
std::unique_ptr<MyClass> myclassptr {nullptr};
if(use_int) {
myclassptr.reset(MyClass<int>);
} else {
myclassptr.reset(MyClass<double>);
}
myclassptr->foobar();
/* [more code making use of myclassptr] */
So this code is (of course) not compiling, because the unique_ptr template must be specified also with the template type. However, then the problem arises that the template type must be the same for all objects assigned using reset.
One ugly solution would be to copy the code myclassptr->foobar(); and the following into each branch of if/else, which I really don't like.
I would like to see a solution similar to this:
/* [Read parameter and write result to bool use_int] */
MyClass<use_int ? int : double> myclass;
myclass.foobar();
What I have read so far is that something like this is also not possible.
Does anybody have a nice solution for this?
The simplest way to do this is:
class IClass{
virtual ~IClass {}
virtual void foobar()=0;
};
template<typename T>
class MyClass:public IClass {
public:
void foobar() override {
// code here
}
};
std::unique_ptr<IClass> myclassptr {};
if(use_int) {
myclassptr.reset(new MyClass<int>());
} else {
myclassptr.reset(new MyClass<double>());
}
myclassptr->foobar();
boost::variant would be another solution, but is usually used for unrelated types. Type erasure could be done, but again that is usually done when you have unrelated types you want to impose a uniform interface on.
In other languages generics look sort of like templates, but are actually an abstract interface with auto-generated typecasting and some typechecking added. C++ templates are function or class compile time factories. Two outputs of such factories are unrelated at runtime by default, and you can add such relations if you want.
Depending on what you want, you can make MyClass a variant type that holds either an int or a double, or you could use type erasure to hide the implementation behind an interface. The Boost.Variant library can help to implement the former.
I am trying to implement a hashtable in C++ that sort of like the Java version
I would like it has the form of
template <class Key, class Value>
class hashtable {
...
}
Soon enough I notice that I need to somehow convert Key into a number, so that I can use the simple hash function
int h(int hashkey) {
return hashkey%some_prime;
}
But the headache is, Key type is only known at run time. Is it possible to check what type Key is on run time in C++. Or I have to create this hashtable class with different type manually? That is easier to do but ugly. Anyone know an elegant solution?
C++ templates are usually duck typed, meaning that you can explicitly cast to an integeral type in the template, and all types that implement the appropriate conversion can be used as a key. That has the disadvantage of requiring that the classes implement the conversion operator in such a fashion that the hash function will be decent, which is asking for a lot.
You could instead provide a function template
template<typename T> int hash (T t);
Along with specializations for the built in types, and any user that wants to use a custom class as key will just have to provide his own specialzation. I think this is a decent approach.
You seem to have a few misunderstandings. Key type is known at compile time - that's the whole point of using templates. Secondly, there is really no such thing as a completely generic hash function that will work on any type. You need to implement different hash functions for different types, using function overloading or template specialization. There are many common hash functions used for strings, for example.
Finally, C++11 includes a standard hash table (std::unordered_map) which you can use instead of implementing your own.
If you would like try to implement a "generic" one, perhaps you can start with a skeleton much like this:
template <class T, class K>
struct HashEntry { // you would need this to deal with collision
T curr;
K next;
}
template <class V, size_t n>
class HashTable {
void insert(V v)
{
...
size_t idx = v->getHashCode(n);
...
}
private:
HashEntry <V> table_[n];
}
It is usually instantiated with some pointer type, to figure out where a pointer should go, it requires the type implement member function "getHashCode" ...
I am writing a few algorithms to build random forests, each forest will be
trained on separate data with separate functions (each tree will use a set of
functions with a fixed signature however different trees will be trained using
different sets of functions which could have a different signature), however I
would like to just write the code to build the random trees once, using
templates. I currently have something like the following:
template class T corresponds to the training data type (i.e. image patch, or
pixel) template class V corresponds to the function pointer type
template<class T, class V>
class RandomTree{
void build(RandomTreeNode<T>& current_node,
vector<V>& functions,
vector<T>& data) {
... some code that basically calls a function passing in data T
}
}
and I create the object like so:
typedef double (*function_ptr)(TrainingDataPoint& data_point);
RandomTree<TrainingDataPoint, function_ptr> tree = ...
The problem is that, for efficiency reasons, for one of the trees I'm
building, I want the set of functions (function_ptr's) to take in not only the
TrainingDataPoint(template type T) but a cache of data. So that my function
pointer will look like:
typedef double (*function_ptr)(TrainingDataPoint&,
unordered_map<string, cv::Mat>& preloaded_images);
Now the problem is, I cant think of a way to keep the RandomTree class generic
but have some function sets (template type V) that take more than just the
training point (template type T).
So far I have thought of:
Making the cache global so that the functions can access it
adding a pointer to the cache to each training data point (but who is responsible for the clean up?)
Adding a third template parameter to the RandomTree, but in this case if I am building a tree that doesn't require this third parameter, what do I put there?
None of these options seem particularly appealing to me, hopefully someone can lend some experience and tell me of a better way?
Thanks
Use a functor for the functions that need state. A functor in C++ is a class (or struct) with an overloaded operator(), so that an instance of the functor can be "called like" a function. The arguments to the functor in the RandomTree should be exactly those parameters that vary and are under the control of the RandomTree, the rest should be bound outside. A sample functor with additional state that wraps a function:
template<typename Retval, typename Arg1, typename ExtraData>
struct BindExtraData
{
typedef Retval(*func_type)(Arg1, ExtraData);
BindExtraData( ExtraData const& d_, func_type func_ ):d(d_), func(func_) {};
ExtraData d;
func_type func;
Retval operator()( Arg1 a1 )
{
return func(a1, d);
}
};
but you can do better. If this is a one-off, there is no need to make it a template. bind2nd(well, binder2nd) is the standard library version of the above, and will be better written.
Can you add another paramter to RandomTree that takes in a Cache. The default would be an empty cache if not provided. For example
template<typename T, typename V, typename CacheDataType = EmptyCache>
class RandomTree{ ... }
RandomTree<TrainingDataPoint, function_ptr, ProloadedImageCache>
I'm pretty sure the answer is "you can't use templates, you have to use virtual functions (dynamic polymorphism)", but it seems like I'd have to duplicate a lot of code if I went that route. Here is the setup:
I currently have two classes, ColorImageSegmentation and GrayscaleImageSegmentation. They do essentially the same thing, but there are three differences
- they operate on different types (ColorImage and GrayscaleImage)
- a parameter, the dimensionality of the histogram (3 vs 1) is different
- The PixelDifference function is different based on the image type
If I create a class
template <TImageType>
class ImageSegmentation
{
};
I would be in good shape. However, I want to have this object as a member of another class:
class MyMainClass
{
ImageSegmentation MyImageSegmentation;
};
But the user needs to determine the type of MyImageSegmentation (if the user opens a grayscale image, I want to instantiate MyImageSegmentation<GrayScaleType>. Likewise for a color image, MyImageSegmentation<ColorType>.)
With derived classes, I could store a pointer and then do:
class MyMainClass
{
ImageSegmentation* MyImageSegmentation;
};
... user does something...
MyImageSegmentation = new ColorImageSegmentation;
but how would I do something like this with templates? The problem is I have a lot of:
typedef TImageType::HistogramType HistogramType;
typedef TImageType::PixelType PixelType;
sort of things going on, so I don't know how I would convert them to the dynamic polymorphic model without duplicating a whole bunch of code.
Sorry for the rambling... does anyone have any suggestions for me?
Thanks,
David
Maybe there are additional requirements you haven't told us about, but from what you have so far, you can pass the type down through the containing class:
template<typename TImage>
class MyMainClass
{
ImageSegmentation<TImage> MyImageSegmentation;
};
Most likely you'll need some layer of dynamic dispatch, but only at the highest level of abstraction:
struct IMainClass
{
virtual bool SaveToFile(std::string filename) = 0;
virtual bool ApplySharpenFilter(int level) = 0;
...
};
template<typename TImage>
class MyMainClass : public IMainClass
{
ImageSegmentation<TImage> MyImageSegmentation;
public:
virtual bool SaveToFile(std::string filename);
virtual bool ApplySharpenFilter(int level);
};
IMainClass* pMain = new MyMainClass<GrayscaleImage>();
You want to create a templated version of your objects but have those objects take different parameter types based on the templated parameter? That's not a very easy thing to integrate into a library but there are a few ways of going about it.
Take a look at unary_function for inspiration. There they are using templated traits to carry around the type parameters without having to work any sort of magic:
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
};
'unary_function' does not contain any functionality other than declaring typedefs. These typedefs, however, allow you to express in code and at compile time named equivalents between code segments. They leverage the way template parameters are checked.
What this means is that you can have objects that work on this:
template<typename T>
struct Foo{
typedef typename T::argument_type argument_type;
Foo(T _myFunc) : m_Func(_myFunc)
void myWrappedFunction(argument_type _argument){ m_Func( _argument ); }
};
which contains within it the value type of the arguments without having to specify them in advance. So if you have pixel_type or something similar for each of your image objects then simply stating typename T::pixel_type will call forward the type parameter you need.