I've got some template code that I'm trying to refactor. Specifically, it's a geometric type, templated by parametric dimension (so it can represent a curve, surface, volume, hypervolume, and so forth), as well as point type.
The problem is that it is getting really unwieldy to edit in such a generic way, and most of the time we only ever use parametric dimensions 1, 2, and 3. The partial specializations are the only things that are changing these days, the shared code is quite stable and complete.
Aside from the difficulty in editing the code, there are also some performance problems that stem from having to store the internal data in a way that generalizes to a grid of arbitrary dimension.. it is possible to mitigate the perf problems in generic ways, but that would just continue to add a lot of unnecessary complexity. Basically the problem is that the templates are too generalized.
So, I'm going to replace the generic template code with 3 separate templates, one for each dimension. I also want to keep the templating of the point type, so I don't want to just use plain classes.
If I had done templating the C way with macros and #including files multiple times, I could run the input through the preprocessor and get the 3 different versions that I want.
While I could do it by hand, I'd prefer an automated solution, at least as a starting point.
Are there any similar methods or refactoring solutions that exist for C++, to get the source for a template with a specific input?
To be a bit more concrete, I have code like this:
template< int Dimension, class PointType > class Nurbs { ... }
template< class PointType > class NurbsCurve : public Nurbs< 1, PointType > { ... }
template< class PointType > class NurbsSurface : public Nurbs< 2, PointType > { ... }
template< class PointType > class NurbsVolume : public Nurbs< 3, PointType > { ... }
But I want to end up with code like this:
template< class PointType > class NurbsCurve { ... }
template< class PointType > class NurbsSurface { ... }
template< class PointType > class NurbsVolume { ... }
This is not really answering your question, but it's an alternative way to keep the templated code.
If I understand correctly, your code has so many specialisations that it becomes unwieldy. One way to deal with this is to use some helper template class dealing with all the details and call its static members from the other templates. The helper class would have a base implementing generic (dimension-independent code) and then there will be specialisations which only override whatever needs to be overridden for the specific dimension.
namespace details {
template<int Dimension> struct helper_base // generic code
{
static_assert(Dimension>1,"missing specialisation Dimension=0,1");
static const int Last = Dimension-1;
template<typename T>
static T dot_product(const T*a, const T*b) noexcept
{ return helper<Last>::dot_product(a,b) + a[Last]*b[Last]; }
};
template<> struct helper_base<1>
{
template<typename T>
static T dot_product(const T*a, const T*b) noexcept
{ return a[0]*b[0]; }
};
template<int Dimension> struct helper // special code for certain dimensions
: helper_base<Dimension> {};
template<> struct helper<3> : helper_base<3>
{
// any code that is particular to 3D.
template<typename T>
static void cross_product(T*p, const T*x, const T*y) noexcept
{
p[0] = x[1]*y[2] - x[2]*y[1];
p[1] = x[2]*y[0] - x[0]*y[2];
p[2] = x[0]*y[1] - x[1]*y[0];
}
};
}
template<typename T, int Dimension>
struct point
{
using helper = details::helper<Dimension>;
T X[Dimension]; // for instance
T operator*(point const&x) const noexcept { return helper::dot_product(X,x.X); }
// etc.
};
template<typename T>
point<T,3> operator^(point<T,3> const&x, point<T,3> const&y) noexcept
{
point<T,3> result;
details::helper<3>::cross_product(result.X,x.X,y.X);
return result;
}
Not sure it answer your question:
You may remove inheritance, and use a member, so instead of:
template<class PointType> class NurbsCurve : public Nurbs<1, PointType> { ... };
template<class PointType> class NurbsSurface : public Nurbs<2, PointType> { ... };
template<class PointType> class NurbsVolume : public Nurbs<3, PointType> { ... };
Use something like:
template<class PointType> class NurbsCurve { ... private: Nurbs<1, PointType> data; };
template<class PointType> class NurbsSurface { ... private: Nurbs<2, PointType> data; };
template<class PointType> class NurbsVolume { ... private: Nurbs<3, PointType> data; };
Note:
- You may have to copy prototype of Nurbs in each class.
- Later if needed, you may replace Nurbs by a specific implementation.
Related
Let's assume I have the following classes:
template<typename A> class Foo { ... };
template<typename A, typename B = Foo<A>> class Bar { ... };
Bar is virtual, and it can be derived with many different arguments for A and B. The template's purpose is to provide intelli-sense for the derivations. I do not want to use interfaces for A and B since they have nothing in common. Also, it would cause a lot of unnecessary casting.
The problem is that I also want to provide various algorithms that use Bar, some generic ones, and some are specialized. Something I tried looks like this:
template<typename A, typename B = Foo<A>, typename BarType = Bar<A, B>>
class Algorithm
{
void doWork(BarType& bar) { ... };
};
What I want to do is pass a derivation from Bar to the Algorithm, and it should automatically detect the arguments A and B. For example:
class BarDerivation : Bar<int, Foo<int>> { ... };
Algorithm<BarDerivation> alg;
This answer provides a solution using type-traits, the problem is that Algorithm would lose the information that BarType is from type Bar.
I'm not certain if what I'm doing is the best approach for what I want to achieve. So is there a solution that solves my problem, or are there better approaches?
Simpler would be to add alias in Foo/Bar:
template<typename A> class Foo { using type = A; };
template<typename A, typename B = Foo<A>> class Bar { using T1 = A; using T2 = B; };
class Derived : Bar<int, Foo<float>> { /*...*/ };
template <typename BarType>
class Algorithm
{
using A = typename BarType::T1;
using B = typename BarType::T2;
void doWork(BarType& bar) { ... };
};
unfortunately my actual template is too full of stuff that is unrelated to my question, so i tried to put everything in a short example. Lets say, I have written the following template:
#include <vector>
template <typename T> class MyTemplate{
public:
typedef void(*MyFunc)(T);
void addFunc(MyFunc f){myFuncs.push_back(f);}
void callFuncs(T value){
for (std::size_t i=0;i<myFuncs.size();i++){myFuncs[i](value);}
}
private:
std::vector<MyFunc> myFuncs;
};
I learned already, that I can specialize this template to behave different when the passed type is a vector, so I wrote this:
template <typename T> class MyTemplate<std::vector<T> > {
public:
typedef void(*MySingleElementFunc)(T);
void addSingleElementFunc(MySingleElementFunc f){
this->mySingleElementFuncs.push_back(f);
}
void callFuncs(std::vector<T> value){
//for (std::size_t i=0;i<myFuncs.size();i++){
// myFuncs[i](value);
//}
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t i=0;i<value.size();i++){
mySingleElemetnFuncs[i](value[i]);
}
}
}
private:
std::vector<MySingleElementFunc> mySingleElementFuncs;
};
Now my question is, what is the most elegant way (if possible without inheritance) not only to specialize the template for the case of vector< T > but at the same time still being able to use the first templates methods where vector< T > is the template parameter. What I would like to do later is the following
void Func1(int i){}
void Func2(std::vector<int> i){}
MyTemplate<std::vector<int> > myTemplate;
myTemplate.addFunc(Func1);
myTemplate.addFunc(Func2);
Is it possible to achieve this without simply copy&paste all stuff I need from the original template, to do the same also with the specialized version? I guess I will have to use some kind of inheritance. However, I want to avoid something like this:
MyTemplate<std::vector<int> > myTemplate;
// myTemplate.addFunc(Func1); // does not work
myTemplate.addFunc(Func2);
MyVectorTemplate<std::vector<int> > myVectorTemplate;
myVectorTemplate.addFunc(Func1); // works
myVectorTemplate.addFunc(Func2);
i.e. the functionality should be determined only by the type passed to the template but not by choosing the appropriate subclass. Anyhow, I have to admit that I am a bit confused about how to inherit in this case. If it was not a template, I could write something like
class MyVectorClass : public MySingleObjectClass {}
However, the following does not make any sense:
template <typename T> MyTemplate<std::vector<T> > : public MyTemplate<std::vector<T> >
but in some sense, this is what I would like to have.
I am sorry for such a long post and I hope it is more or less clear what is my problem...
EDIT: I just found a mistake in the above code. The loop in the vector template should read
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t j=0;j<value.size();j++){
mySingleElemetnFuncs[i](value[j]);
}
}
i.e. each registered function should be called once for each entry in the vector. (Otherwise the template does not work if the number of registered functions is not equal to the size of the vector.)
In fact you want add functionality to the specialization, something like:
template <typename T> class MyTemplate<std::vector<T> >
{
public:
typedef void(*MySingleElementFunc)(T);
typedef void(*MyVectorFunc)(std::vector<T>);
void addSingleElementFunc(MyVectorFuncf){
this->myVcetorFuncs.push_back(f);
}
void addSingleElementFunc(MySingleElementFunc f){
this->mySingleElementFuncs.push_back(f);
}
void callFuncs(const std::vector<T>& value){
for (std::size_t i=0;i<myVectorFuncs.size();i++){
myVectorFuncs[i](value);
}
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t i=0;i<value.size();i++){
mySingleElemetnFuncs[i](value[i]);
}
}
}
private:
std::vector<MySingleElementFunc> mySingleElementFuncs;
std::vector<MyVectorFunc> myVectorFuncs;
};
template <typename T>
class MyTemplateBase {
// generic stuff goes here
};
template <typename T>
class MyTemplate : public MyTemplateBase<T> {
// nothing goes here
};
template <typename T>
class MyTemplate<std::vector<T>> : public MyTemplateBase <std::vector<T>> {
// specialized stuff goes here
}
If you don't want public inheritance you can use private inheritance, but then you would have to explicitly export everything inherited privately:
template <typename T>
class MyTemplate<std::vector<T>> : private MyTemplateBase <std::vector<T>> {
public:
// generic stuff re-exported
using MyTemplateBase<std::vector<T>>::Func1;
using MyTemplateBase<std::vector<T>>::Func2;
// specialized stuff goes here
}
Might still be worth it, as public inheritance is not exactly the most appropriate tool for code reuse.
I think that, since Vector is a template not a class, should be something like:
template<template <typename ...> class T /*= std::vector*/>
class SomeClass
{
T x;
};
So I have run into a problem in which I need a method to be defined for any types that inherit from a base class that I have created, yet I need that method to be static, is there anyway I can force it to be created?
The reason I need this I will have people be extending my base class, but I need to be able to guarantee a call to a function like so derivedType derivedType::createFromSerialized(std::string) will work to create a new instance from a serialization.
Edit: I am trying to follow Richard J. Ross III's advice and use static_assert however I am running into some problems with that and I have a feeling its due to it being called from a templated class but I can't figure out how to fix it.
template <typename indType> class population {
static_assert(std::is_function<indType::createFromSerialized>::value, "message");
....
};
However that is giving me an error of to refer to a type member of a template parameter, use ‘typename indType:: createFromSerialized’ and no type named 'createFromSerialized' in 'class test'
The reason I am trying to use static_assert is to get a nicer error message that will give information about the proper function signature for createFromSerialized instead of just one that says its not defined.
This can be done by combining static_assert and SFINAE detection technique.
template<typename T, typename V = bool>
struct has_deserialize : std::false_type { };
template<typename T>
struct has_deserialize<T,
typename std::enable_if<
std::is_same<decltype(&T::createFromSerialized),
T* (*)(const std::string&)>::value,
bool
>::type
> : std::true_type { };
template <typename T>
class test
{
static_assert(has_deserialize<T>::value, "No suitable createFromSerialized");
};
What you are trying to accomplish is possible through a factory pattern very easily. Not sure whether you can accomplish it using templates.
Here's a skeleton of how I would go about implementing the serialization functionality.
SerializationFunctor.h
class Base;
class SerializationFunctor
{
virtual Base* operator(FILE* in) const = 0;
};
Base.h
class Base
{
bool registerSerializationFunction(std::string const& identifier,
SerializationFunctor* functor);
};
ConcreteA.h
class ConcreteA
{
};
ASerializationFunctor.cc
class ASerializationFunctor : public SerializationFunctor
{
virtual Base* operator(FILE* in)
{
// Restore ConcreteA and return a pointer.
}
};
bool dummy = registerSerializationFunction("ConcreteA", new ASerializationFunctor());
ConcreteB.h
class ConcreteB
{
};
BSerializationFunctor.cc
class BSerializationFunctor : public SerializationFunctor
{
virtual Base* operator(FILE* in)
{
// Restore ConcreteB and return a pointer.
}
};
bool dummy = registerSerializationFunction("ConcreteB", new BSerializationFunctor());
I'm trying to compile the following code under VC2010.
struct CircValRange
{
double a,b; // range: [a,b)
};
template <struct CircValRange* Range>
class CircVal
{
// todo
};
const CircValRange SignedDegRange= {-180., 180.};
CircVal<SignedDegRange> x;
I'm getting
error C2970: 'CircVal' : template parameter 'Range' : 'SignedDegRange' : an expression involving objects with internal linkage cannot be used as a non-type argument
1> d:\4\circval\circval\circval.h(8) : see declaration of 'CircVal'
1> d:\4\circval\circval\circval.h(13) : see declaration of 'SignedDegRange'
I am trying to define a templated class CircVal that will receive a struct Range as the templated parameter.
I don't want it to be possible to assign classes with one range to classes with another range (I want them to be different types).
How can I do it?
Someone has recommended a constructor parameter, which I second. But you can still do it as originally desired
struct CircValRange
{
double a,b; // range: [a,b)
};
template <CircValRange const& Range>
class CircVal
{
// todo
};
extern const CircValRange SignedDegRange= {-180., 180.};
CircVal<SignedDegRange> x;
But notice that the property that determines the type-identity of CircVal<SignedDegRange> is not the value of SignedDegRange, but the address/identity of it. That is, the following does not work because CircVal<SignedDegRange1> denotes a different type
extern const CircValRange SignedDegRange1 = {-180., 180.};
CircVal<SignedDegRange1> y = x; // error!
As such, an enumeration may be better suited for this
enum RangeKind {
SignedDegRange,
UnsignedDegRange
};
const CircValRange Ranges[] = { { -180., -180. }, { 0., 360. } };
template <RangeKind Range>
class CircVal
{
// todo
};
Or even a traits class with static member functions, similar to a solution someone else had
template <typename Range>
class CircVal
{
// todo
};
struct SignedDegRange {
static double min() { return -180.; }
static double max() { return 180.; }
};
CircVal<SignedDegRange> x;
Instead of making it a template, why don't you reqire a range as a constructor parameter?
struct CircValRange
{
double a,b; // range: [a,b)
};
class CircVal
{
public:
CircVal(const CircValRange &_range) : range(_range) {}
private:
CircValRange range;
// todo
};
const CircValRange SignedDegRange= {-180., 180.};
CircVal x(SignedDegRange);
That way each instance of a CircVal will have an associated range. Then you can override the assignment opearator to prevent assignment with different values.
Or, if you're interested in a different way with templates, you could do something like this for a range:
template <int MIN, int MAX>
class range {
static const int min = MIN, max = MAX;
};
template <class T>
class CircVal {
//todo
};
CircVal< range<10,20> > x;
But of course, that's not very clean or usable.
template <class Range>
class CircVal
{
// todo
};
or
template <class Range> class CircVal;
template<>
class CircVal<CircValRange> {...
to instantiate
CircVal<CircValRange> ...
I think you are omitting one step. If you want to create a template CircVal that you can specialise on a type, you write:
template<typename Range>
class CircVal
{
...
};
and if you then want to specialise it on CircValRange, you create an instance of it as you do further down in your code.
What you seem to try and enforce is that it'll only accept classes derived from a certain base class but unfortunately that's not quite the way templates work - you'll have to find another way to enforce that, maybe by duck typing.
I recently saw some code using macros like
#define CONTAINS(Class, Name)\
private:\
std::list<Class> m_##Name##s;\
public:\
void add_##Name(const Class& a_##Name) {\
m_##Name##s.push_back(a_##Name);\
}\
int get_##Name(int pos) {\
return m_##Name##s.at(pos);\
}\
// ... more member functions
Later you can declare a class like
class my_class {
CONTAINS(int, integer)
// ...
};
and write
my_class a(...);
a.add_integer(10);
I was puzzled about this paste-in-macro-style because I'm missing concrete counter-arguments. But beside that I accept the following pros
you can easily add a list interface for arbitrary types to your class
you avoid frequently repeated code
you have an easy to use interface (like add_integer(10))
Now I'm searching for alternatives which meet all these points above and avoid this old C macro style. My first idea was to create an abstract base class template
template<typename T>
class list_interface {
private:
std::list<T> m_list;
public:
void add_element(const T& x) {
m_list.push_back(x);
}
// ... more member functions
};
and add it to my class via inheritance like this
class my_class : public list_interface<int> {
// ...
};
Now I can write too
my_class a;
a.add_element(10);
but I'm concerned about the following points:
you can only add one list to your class
you publicly inherit from a class without virtual destructor
I don't meet the third point of the pros (add_element(10) instead of add_integer(10))
My questions are:
What are the drawbacks of the old C macro construct
How can I provide a similar functionality without macros
How about:
#include <vector>
template<typename T>
class Plop
{
std::vector<T> data;
public:
void add(T const& v) {data.push_back(v);}
T get(int pos) {return data.at(pos);} // at() is not valid on lists.
};
class my_class
{
public:
Plop<int> integer;
Plop<float> floater;
};
int main()
{
my_class x;
x.integer.add(5); // similar to x.add_integer(5);
x.integer.get(0); // similar to x.get_integer(0);
}
It meets all the requirements:
you can easily add a list interface for arbitrary types to your class
you avoid frequently repeated code
you have an easy to use interface (like add_integer(10))
My questions are:
What are the drawbacks of the old C macro construct
The ick factor.
Debugging.
Can pass individual list to other functions or methods.
How can I provide a similar functionality without macros
See above.
my opinion
1) Yuck yuck. Complex macro which will hinder debugging. Just the view of the macro makes my skin crawl.
2) Your inheritance solution looks fine. If you really needed multiple lists of different types, you might want to consider just writing more code and instantiating the list as a member variable. There really is no benefit of attempting to reduce lines of code by making it convoluted.
There is a way, in meta-programming fashion, and using tags.
First, let's consider the roll your own solution.
The idea is to come up with this interface:
class my_class : public vector<Name, std::string>, public vector<Foo, int>
{
};
And then, to use it like this:
my_class a;
a.add<Name>("Peter");
a.add<Foo>(3);
Now, lets dive behind the covers. We are going to use SFINAE combined with enable_if.
template <class Tag, class Type>
class vector
{
template <class T, Return>
struct Enable
{
typedef typename boost::enable_if<
boost::is_same<T,Tag>,
Return
>::type type;
}; // Enable
public:
template <class T>
typename Enable<T,void>::type
add(Type const& i) { m_elements.push_back(i); }
template <class T>
typename Enable<T, Type const&>::type
get(size_t i) const { return m_elements.at(i); }
// You'd better declare a whole lot of other methods if you really want that
// like empty, size and clear at the very least.
// Just use the same construct for the return type.
protected:
vector() : m_elements() {}
vector(vector const& rhs) : m_elements(rhs.m_elements) {}
vector& operator=(vector const& rhs) { m_elements = rhs.m_elements; return *this; }
~vector() {} // Not virtual, because cannot be invoked publicly :)
private:
std::vector<Type> m_elements; // at() is inefficient on lists
};
How does this work ?
Basically when you invoke get<Name> the compiler has 2 alternatives:
vector<Name,std::string>::get
vector<Foo,int>::get
Now, thanks to enable_if, the second alternative is ill-formed (the type deduced cannot be used because Foo != Name), and thus, thanks to SFINAE, this alternative is removed from the list without any complaint.
Then, since there is only one alternative, it gets selected. And of course, since this is done at compile-time, you don't actually have any runtime penalty.
If you want to skip some work (for this type). You could also simply use a simpler construct:
template <class Tag, class Embedded>
class Embed
{
// redeclares same private and protected interface
public:
template <class T>
typename Enable<T,Embedded &>::type get() { return m_element; }
template <class T>
typename Enable<T,Embedded const&>::type get() const { return m_element; }
private:
Embedded m_element;
};
Then you use it like so:
class my_class: public Embed< Names, std::vector<std::string> >,
public Embed<Foo,int>
{
};
my_class a;
std::vector<std::string> const& names = a.get<Names>();
int foo = a.get<Foo>();
a.get<Names>().push_back("Peter");
It's easier since you only provide accessors and don't have to write a whole bunch of methods just to forward the work.
And now that we've work so much, we should ask ourselves: this seems quite practical and generic, surely there is a library or something ?
There is >> Boost.Fusion's map:
class my_class
{
public:
template <class Tag>
typename result_of::at_key<map_type, T>::type &
get() { return at_key<T>(m_data); }
template <class Tag>
typename result_of::at_key<map_type, T>::type const&
get() const { return at_key<T>(m_data); }
private:
// First element of the pair: TAG
// Second element of the pair: Actual type of the data
typedef boost::fusion::map <
std::pair<Name, std::vector<std::string> >,
std::pair<Foo, int>
> map_type;
map_type m_data;
};
The main issue with the macro is: it is solving a problem you don't really have.
It is making a class with list members, where the lists are manipulated directly.
Because we think in OO, members should be encapsulated and we want to use DRY, we come to this construct, while my_class remains really a data-class.
If all the class has to do is contain lists, turn it into a struct and keep the lists public.
This way you have a clean intention and the lists can be accessed the STL-way.
If the class needs to have control over the lists, then you shouldn't expose the lists and the macro's are of little use.
So my code would be (not compiled):
struct my_class {
std::list<int> integers;
std::list<std::string> names;
// ...
};
int main()
{
my_class lists;
lists.integers.push_back(5);
size_t size_names = lists.names.size();
}
Pro:
easily add lists
no code duplication
consistent (STL) interface
straightforward
no macro's
Con:
no data encapsulation, if that would be a requirement
For multiple lists, you can try multiple inheritance with typedefs. Something like:
class my_class : public list_interface<int>, public list_interface<float> {
public:
typedef list_interface<int> Ints;
typedef list_interface<float> Floats;
//...
};
and use like:
my_class a;
a.Ints::add_element(10);
a.Floats::add_element(10.0f);