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) { ... };
};
Related
I'm trying to find the best method to have a kind of "object" that can be either specialized or "linked" to another type.
For instance you cannot specialize a class to make it become a simple int, and you cannot use the keyword using to specialize classes.
My solution is the following:
template<class Category, Category code>
struct AImpl
{};
template<class Category, Category code>
struct AHelper
{
using type = AImpl<Category, code>;
};
template<class Category, Category code>
using A = typename AHelper<Category, code>::type;
template<int code>
void doSomething(A<int, code> object)
{
}
template<>
struct AImpl<int, 5>
{
double a;
};
template<>
struct AImpl<int, 6>
{
int b;
double c;
};
template<>
struct AHelper<int, 7>
{
using type = int;
};
template<class Category, Category code>
struct Alternative {};
template<int code>
void doSomethingAlternative(Alternative<int, code> object)
{
}
This works but you need to specify the code parameter in doSomething, and I would like to avoid that.
For instance:
A<int,7> a7; // This is equivalent to int
a7 = 4;
A<int, 5> a5; // This is equivalent to AImpl<int,5>
a5.a = 33.22;
doSomething(a5); // This does not compile
doSomething<5>(a5); // This compiles but is bulky
Alternative<int,0> alt0;
doSomethingAlternative(alt0); // This compiles and is not bulky
// but you're forced to use class
// specializations only
Is there a way to achieve what I want? It's ok to change both doSomething or the A implementation.
If you are trying to customize the behavior of doSomething based on the type it is called with, you cannot have the compiler deducing stuff from AHelpr::type (as previously answered). But you can tell it what it needs to know by providing a customization point in the form of traits. For instance:
template<typename T>
void doSomething(T& object)
{
auto code = SmthTriats<T>::code;
}
This is highly extendable given the ability to specialize SmthTriats:
template<typename> struct SmthTriats;
template<typename Category, Category code_>
struct SmthTriats<AImpl<Category, code_>> {
static constexpr auto code = code_;
};
template<>
struct SmthTriats<int> {
static constexpr auto code = 7;
};
A traits class allows for customization outside your module too. Client code need only specialize SmthTriats with their own type, and so long as they respect the contract you laid out with your trait, your code will work for them.
I got two classes, a B class has a member A1, and the A1 class has a reference member B, this is easy to write like this:
class B;
class A1 {
public:
A1(const B& b) : b_(b) {}
private:
const B& b_; // a reference to B
};
class B {
public:
B(A1 a1) : a1_(a1) {}
private:
A1 a1_; // a Type A1 member
};
And then I need change class B to a template class, so the code should be like this:
template<typename T1>
class B;
class A1 {
public:
A1(const B<A1> &b) : b_(b) {};
private:
const B<A1> &b_; // a reference to B<A1>
};
template<typename T1>
class B {
public:
B(T1 t1) : t1_(t1){}
private:
T1 t1_; //a T1 type member
};
And suddenly we need a second member in B, so I changed the B to this:
template<typename T1, typename T2>
class B {
public:
B(T1 t1, T2 t2) : t1_(t1), t2_(t2){}
private:
T1 t1_;
T2 t2_;
};
This got a problem:
now if I'm a coder of A, the code below is illegal:
template<typename T1, typename T2>
class B;
class A1 {
public:
A1(const B<A1> &b) : b_(b) {}; //wrong, need a second template argument
private:
const B<A1> &b_; // wrong, either
};
That means the coder must fill the second template argument which he may not know (or at least, may not care about). So I change the code to this:
template <typename T1, typename T2>
class B;
template <typename TB>
class A1 {
public:
explicit A1(const TB& b) : b_(b) {}
private:
const TB& b_;
};
template <typename TB>
class A2 {
public:
explicit A2(const TB& b) : b_(b) {}
private:
const TB& b_;
};
template <typename T1, typename T2>
class B {
public:
B(T1 a1, T2 a2) : a1_(a1), a2_(a2) {}
private:
T1 a1_;
T2 a2_;
};
This looks nice except I don't know how to make a B instance(like this:B<A1<B<A1<...>,A2>, A2>, it's recursively.)
The ideal design I'm looking forward to is that programmers for A1 and A2 simply do not need to know each other, and the programmer for B is simply add A1 and A2 more or less like this B<A1, A2>(or add some other stuff), and even if he add a T3 parameter like B<A1, A2, A3>, the code ofA1andA2` will not need to be changed.
So
1: If I insist in this syntax, does this mean I have to give up using template for B, instead use pointers?
2: If I insist in using template, does this mean the class T1 and class T2 must know each other?
3: Is there a third way by using template while T1 and T2 is independent? That is, no matter how many parameters I add to class B, the A1 class does not need to change? Template template/CRTP/SFINAE, all of this seems not useful. As the B class is only a reference in class A, the B class is more like a interface rather than a certain class, this remind me of the C++ proposal "concept", can "concept" help in this case?
4: Is this a xy problem? That means I should not design my code pattern in this way?
Here's how one might do that.
// B doesn't know about A
template <class T1, class T2>
class B {};
// A doesn't know about B
template <template<class> class TB>
class A {
using MyB = TB<A<TB>>;
};
template <class K>
using Bint = B<K, int>;
int main() {
A<Bint> abint;
}
Edit: If B has more than one template parameters, this can also be done, though a bit more complicated. One needs to tie all the template parameters in one class using some helpers. Here's an example. (I have renamed the classes for clarity).
// The top class parameterised by 3 bottom classes
template <class A1, class A2, class A3>
struct Top {};
// Three bottom classes parameterised by the top
template <template<class> class T> struct Bottom1 {};
template <template<class> class T> struct Bottom2 {};
template <template<class> class T> struct Bottom3 {};
// Until this point, none of the classes know about any other.
// Now tie them together with these helper definitions.
template <typename K>
using BundledTop = Top<typename K::A1, typename K::A2, typename K::A3>;
struct Bundle
{
using A1 = Bottom1<BundledTop>;
using A2 = Bottom2<BundledTop>;
using A3 = Bottom3<BundledTop>;
};
using MyTop = BundledTop<Bundle>;
I would say that your answer 4 is this right one: this seems as being a flawed design. I cannot prove that but I would like to give you an example.
I have implemented something similar to your code when I have been implementing bounding volume hierarchies. You could think of B as a branch class and A as a leave class of the tree (that is not completely correct, but should give an idea). Every branch has to contain its leaves, therefore B stores instances of A. But it is also nice to go back from a leave to its branch, therefore A should store a reference to B. You could decide to make your bounding volume hierarchy store arbitrary content (triangle, quads, polygons), therefore the item type should be a template parameter. Also you might decide to make the maximum leave number of each branch a template parameter of B.
But why should the branch class be able to store leaves that are made for arbitrary branches (because the B type is a template parameter of A)? If B stores instances of A, then I cannot think of any reason for making the B type a template parameter of A.
So probably you are too general here and should look for another design.
I am looking forward to your comments.
I would like to achieve the following behavior
struct A {
};
template <bool arg>
struct B = A; // ERROR: THIS IS NOT A VALID LINE
template <>
struct B<false> {
// Specific implementation of B
};
In other words, if a template argument arg is true the struct B should match struct A exactly, otherwise I would like to provide my own implementation. Is there an elegant way to achieve that?
I can think of two possible approaches but neither attract me.
A workaround with help of using clause. I don't like this because I had to rename a class that contains a specific implementation of B. I don't want to introduce another struct C. It still should be called B not C.
struct A {
};
struct C {
// Specific implementation of B
};
template <bool arg>
using B = typename std::conditional<arg, A, C>::type;
Using inheritance. I don't like this approach because I want struct B to be an exact copy (alias) of struct A but not a derived class. Since constructors are not inherited I would probably have put extra lines to deal with that. All these extra lines do not bring any real functionality but just mimics the "assignment" operator that I need. Moreover, extra lines are source of possible overhead.
struct A {
};
template <bool arg>
struct B : public A
{
};
template <>
struct B<false> {
};
P.S. I am inclined to to use another namespace and using clause together
struct A {
};
namespace arg_false {
struct B {
// Specific implementation of B
};
}
template <bool arg>
using B = typename std::conditional<arg, A, arg_false::B>::type;
I have some code that compiles and works fine in C++ (as long as I forward declare the generic template class, then the specialized instance, and then define the generic template class - see inheriting from class of specialized self?). When I try to use SWIG to add C# bindings to the class, however, it either crashes SWIG or doesn't include the methods from the inherited class. I believe this is only possible in C++11, but I'm not sure as I haven't tried this with an older compiler.
Here's a toy example:
template <typename T, int N = 0> class A;
template <typename T> class A<T, 0>
{
public:
A() : mFoo(NULL) {}
virtual ~A() {}
T* getFoo() { return mFoo; }
protected:
T* mFoo;
};
template <typename T, int N = 0> class A : public A<T, 0>
{
public:
A() : A<T, 0>(), mBar(N) {}
virtual ~A() {}
int getBar() const { return mBar; }
protected:
int mBar;
};
In a program, I can then instantiate an instance of A<char,10> (for example), and have access to mFoo and mBar, or just instantiate an instance of A and only have access to mFoo. I can also use methods with parameters like
void baz(A<T, 0>* anyA)
and the method will accept A<T, 0> or A<T, n> instances.
For context and explanation, this pattern works well for containers that can be either dynamic or fixed size. If they are dynamic, you can just instantiate it as a A<T, 0> and not have the overhead of inheritance, etc. or you can have a fixed-sized container (A<T, N> where N > 0) that does use inheritance, but has access to all the "base" class methods, can override them as needed, and still be accepted as a parameter for methods that accept either dynamic or fixed-sized instances of the container.
However, when I try to use SWIG so that I can use this class in other languages, I run into issues.
At first, I tried something like:
%template(tA) A<char, 0>;
but this causes SWIG to crash (at least in version 3.0.0 that I'm currently using).
Next, thinking that, like all template inheritance in SWIG, I need to have an existing template for the base class as well as the inheritor class (if both are templated anyway). So I tried
%template(tABase) A<char, 0>;
%template(tA) A<char>;
This also causes SWIG to crash.
So, I tried to be a little clever and take advantage of SWIGS ability to use a "nameless" template for classes that are inherited from and did something like:
%template() A<char, 0>;
%template(tA) A<char>;
This avoids the crash and I get an output of the tA class, but it only has the methods, etc. from the inheritor class A<T, N> and does not actually inherit from the A<char, 0> specialized template instance that it needs to and thus I have no access to all the methods and data in the "base" class of A<char, 0>.
Has anyone else tried to get SWIG to handle this? Successfully? Is there a command line param that I can pass to SWIG that will make things work (and stop it from crashing)?
The easiest way I can see to solve your problem is to stop being so fancy that you confuse the other languages, by being fancier within C++:
template<typename T>
struct A0_impl;
template<typename T, typename N>
struct A_impl;
template<typename T, int N>
struct A_helper {
typedef A_impl<T,N> type;
};
template<typename T>
struct A_helper<T,0> {
typedef A0_impl<T> type;
};
template<typename T, int N=0>
using A = typename A_helper<T,N>::type;
template<typename T>
struct A0_impl {
A0_impl() : mFoo(nullptr) {}
virtual ~A0_impl() {}
T* getFoo() { return mFoo; }
private:
T* mFoo;
};
template<typename T, typename N>
struct A_impl:A0_impl<T> {
A_impl() : A0_impl<T>(), mBar(N) {}
virtual ~A_impl() {}
int getBar() const { return mBar; }
protected:
int mBar;
};
template<typename T>
struct A_impl<T,0>:A0_impl<T> {
A_impl() : A0_impl<T>() {}
virtual ~A_impl() {}
// possibly inherit other constructors from A0_impl
};
this gives you C++ code that behaves nearly exactly like your version, but does away with that descend-from-specialization issue that you believe is causing your problems.
Basically I replaced your A<T,0> specialization with A0_impl, and the template alias A<T,N> now maps to either A_impl<T,N> or A0_impl<T> depending on if N is 0 or not.
The A template alias is optional, as you could instead have A0_impl be called AnySizedA and A_impl be called FixedSizeA, and instead of specializing A<T,0> to do something simply ban it.
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.