Extend anonymous union in template specialization class c++ - c++

Let us suggest I have a class called vec4. Its a template and could be uint8, float or int in most cases. Other cases are allowed but are less likely. The class looks like this:
template<class T>
class vec4 {
public:
vec4(){}
virtual ~vec4(){}
union {
struct {
T x,y,z,w;
};
struct {
T r,g,b,a;
};
};
};
This helps me think about a problem in different ways when writing code and allows me to do other cool things also and I rather enjoy the design pattern when ever applicable.
The problem is I would like to extend the class and add functions in the case it is a 32 bit float. That I can do. I would also like to extend the union for a further maths paradigm where the third members are T c,y,m,k.
I am finding it very difficult to find material on the subject. This code extends the template, allowing specialised functions however, I would also like to extend the union within.
template<>
class vec4<float> {
public:
vec4(){}
virtual ~vec4(){}
};
The following specialisation compiles but doesn't allow me to also access members as an x,y,z,w object though;
template<>
class vec4<float> {
public:
vec4(){
this->i=0;
this->j=0;
this->k=0;
this->l=0;
}
vec4(float a){
this->i = a;
this->j = a;
this->k = a;
this->l = a;
}
union {
struct {
float i,j,k,l;
};
};
};
I was able to add this line:
struct vec4<float>;
to the specialized template. It would compile until trying to access the x,y,z,w members;

May be its possible without intoducing additional name in union, but I don't know how. But with additional name you can do it this way:
template<typename U>
struct ExtraMembers {};
template<class T>
class vec4 {
public:
vec4(){}
virtual ~vec4(){}
union {
struct {
T x,y,z,w;
};
struct {
T r,g,b,a;
};
ExtraMembers<T> extra;
};
};
template<>
struct ExtraMembers<float> {float c, m, y, k;};
int main()
{
vec4<int> a;
vec4<float> d;
// a.extra.c = 0; // Error: No member named 'c'
d.extra.c = 0.;
}
Edit: You can also hide ExtraMembers in anonymous or named namespace, but I don't think its possible to make it internal to vec4.

Related

Workaround for using a private struct

I am using an engine for my console application. This engine can not be changed. The engine contains a class called Mesh. There's a public method in this class findBoundaryLoops() which I'm using in my class (which is not part of the engine) but I have to pass a parameter to this method which type VertexLoop is defined as a private attribute. I'm not sure that I explain it well, so there's a representation of the code:
Mesh.h:
class Mesh final
{
private:
...
struct VertexNode
{
Edge connectingEdgeWithNext;
Vertex vertex;
VertexNode* prev;
VertexNode* next;
float angle;
};
struct VertexLoop
{
VertexNode* firstNode;
uint32_t nodeCount;
template<typename Callable>
void forEachNode(Callable&& f)
{
VertexNode* n = firstNode;
for (uint32_t i = 0; i < nodeCount; ++i, n = n->next)
{
f(n);
}
}
};
...
public:
...
void findBoundaryLoops(memory::MemoryArena& arena, vector<VertexLoop>& loops) const;
...
};
I have to use the findBoundaryLoops() method, but the VertexLoop struct is private. Is there a workaround or something to solve this problem?
This answer has two parts. Below I will show you how to access the type declared in the private section. But I think the important point, and thats why I put it first, is to realize that you should not need the below solution. Anybody can access VertexLoop. The name is private the type not. There was no point to declare it in the private section in the first place. If the type appears on the signature of a public method you can as well put it in the public section.
If this is library code or generated code, then either you misunderstand how to use it, or it can be considered broken.
Simpler example:
#include <vector>
struct foo {
private:
struct bar{};
public:
void f(std::vector<bar>&){}
};
Now we write a trait that given a member function of foo with a single vector parameter tells us the value_type of that vector. Then we instantiate it with a pointer to foo::f to get an alias to bar:
template <typename X>
struct bar_type;
template <typename T> struct bar_type< void(foo::*)(std::vector<T>&)> { using type = T; };
using public_bar = bar_type<decltype(&foo::f)>::type;
Using it:
int main() {
std::vector<public_bar> v;
foo f;
f.f(v);
}
Live Demo
Maybe worth to note that this is by no means comparable to "dirty hacks" by which one can access private members of a class (yes they do exist). This is not a hack, it is perfectly fine partial specialization of a trait to get the parameter type of a public method.
TL;DR Just don't do it. Move VertexLoop to the public section.

optional variable declaration in a template

I want to declare member variables in a class template if some condition from template parameters is true. I could use nested class as container, but it is impossible to do explicite specializations in that case.
I'm trying someting like this:
enum class VarPolice { Declare, DontDeclare };
template<VarPolice vp = VarPolice::Declare>
class MyClass
{
struct EmptyStruct {};
struct VarSaverStruct { int MyVar; };
using VarSaver = typename std::conditional<vp == VarPolice::Declare, VarSaverStruct, EmptyStruct>::type;
VarSaver saver;
}
So, I can use MyVar as saver.MyVar
Is there any way to do optional variable declaration without using EmptyStruct that has a size overhead?
C++17 can be used.
Yes, you can have your cake and eat it too. Just inherit from correct type instead, and rely on the empty base optimization.
enum class VarPolice { Declare, DontDeclare };
struct EmptyStruct {};
struct VarSaverStruct { int MyVar; };
template<VarPolice vp = VarPolice::Declare>
class MyClass : std::conditional_t<vp == VarPolice::Declare,
VarSaverStruct, EmptyStruct>
{
};
Standard library implementations rely on it themselves to "store" allocators without taking up space if they are stateless.

C++ class template for similar classes

I have a socket data type class that is used to read and parse a value from socket stream (may be used for file too).
Let my class be mc_double:
class mc_double {
private:
double value;
public:
bool read(socket);
write(double);
}
Actual class is more complicated, but this is the principle. Now, I need to parse float from the stream. Float is way similar to double, so is already implemented int. Could't I merge this class definitions, with all double, int and float somehow templated?
This is what I mean:
class mc_<typename = double or int or float> {
private:
typename value;
public:
bool read(socket);
write(typename);
}
Some methods would be then defined individualy as mc_double::method() others would be same for all types: mc_typename::general_method(). Also, for some I'd need just minor changes in code:
typename mc_typename::return_value() {
return val;
}
Or the constructor:
mc_typename::mc_typename(<int, long, char, double> number) {
val = (typename)number;
}
The result should be three classes - mc_int, mc_float and mc_double.
I have found the official C++ template docs, but I only figured out the last part of my question - I can create a function that accepts multiple data types. The rest does not seem to be that easy.
You could make your class a class template:
template<typename T, bool base = true>
class mc {
protected:
T value;
public:
bool read(socket);
write(T);
};
This class will contain the member function that are common for all types T. Then, you could specialize this class templates separately for different types and let them inherit from mc<T, true>:
template<>
class mc<double, true> : public mc<double, false> {
public:
// Member functions for double only...
};
template<>
class mc<int, true> : public mc<int, false> {
public:
// Member functions for int only...
};
Make sure the non-public member data of the primary class template are made protected if you want derived classes to access them.
You could then instantiate them this way:
mc<double> m;
mc<int> m;
// ...
If you really want to use the mc_double and mc_int names, then you could either:
a) Create type aliases for them:
typedef mc<double> mc_double;
typedef mc<int> mc_int;
b) Change the design of the class template to not use specialization and have one single template parameter, and create the derived classes independently:
template<typename T>
class mc {
protected:
T value;
public:
bool read(socket);
write(T);
};
class mc_double : public mc<double> {
public:
// Member functions for double only...
};
class mc_int: public mc<int> {
public:
// Member functions for int only...
};
You could use templates in the class definition as follows:
template <typename T>
class mc
{
public:
bool write(T _val);
private:
T mVal;
};
but you can't as easily specialize some methods but not others based on the type of T (i.e., you have to specialize the entire class, not just one method). You could solve this with some sort of inheritance hierarchy, where methods that are the same regardless of the type are in the base, and the specialization is in derived classes. So keep the above (assuming write is one that doesn't change) and create:
class mc_double : public mc<double>
{
public:
void doSomethingSpecific() { /* code specific for 'doubles' */ }
};

Using template argument of base class in derived class

Consider the following situation in C++:
template<int n>
class Base { ... };
class Derived3 : public Base<3> {
// a complicated body, making use of n=3
};
class Derived7 : public Base<7> {
// a completely different body, making use of n=7
};
Inside of the Derived3 member functions, I would like to explicitly use n=3, and inside Derived7, n=7, without hardcoding the numbers, i.e., still referring to something like a template argument n. The following options come to my mind:
Also templating the derived classes on n, and then using typedef. This way, the derived classes know n:
template<int n>
class DerivedTemplate3 : public Base<n> { ... };
typedef DerivedTemplate3<3> Derived3;
template<int n>
class DerivedTemplate7 : public Base<n> { ... };
typedef DerivedTemplate7<7> Derived7;
The problem with this is that DerivedTemplateX makes sense for nothing but n=X, so this feels like abusing the template paradigm.
Using a static const member to store n in Base, and referring to that in the derived classes:
template<int n>
class Base {
protected:
static const int nn = n;
...
};
class Derived3 : public Base<3> {
// refer to nn=3
};
class Derived7 : public Base<7> {
// refer to nn=7
};
The problem here is that I seemingly can't use the same identifier (nn vs. n). Also, I'm not sure whether this will allow me to use nn as a template argument for members of the derived classes.
So: how can this be implemented in a non-redundant, efficient way? Maybe using some kind of static const int as a member somewhere?
The standard practice is to use an uppercase letter for the template parameter, then a static const value in lowercase:
template<int N>
class Base {
protected:
static const int n = N;
...
};
Then you use the lowercase static const value n everywhere - don't use N anywhere else.
Also, I'm not sure whether this will allow me to use nn as a template argument for members of the derived classes.
It is a constant expression and so it can be used as a template argument.
Does this work for you?
template<int n>
class Base {
protected:
static const int MyN = n;
};
class Derived3 : public Base<3> {
void f()
{
std::cout << MyN;
}
};
class Derived7 : public Base<7> {
void f()
{
std::cout << MyN;
}
};
int main()
{
}

How to avoid "'identifier' uses undefined class/struct/union 'name'" error when forward declaration is not enough?

According to http://msdn.microsoft.com/en-us/library/9ekhdcxs(v=vs.80).aspx,
C2079 can also occur if you attempt to declare an object on the stack of a type whose forward declaration is only in scope.
class A;
class B {
A a; // C2079
};
class A {};
Possible resolution:
class A;
class C {};
class B {
A * a;
C c;
};
class A {};
My question is how do I eliminate this error when I have the following situation:
class A; // Object
class B // Container
{
public:
typedef int SomeTypedef;
private:
A a; // C2079
};
class A {
void Foo(B::SomeTypedef);
};
I can't declare A before declaring B because A needs to use B's typedef, and I can't declare B before A because of this error.
One possible solution is to use a pointer to A instead of a stack variable, but I don't want a pointer (in this case).
Another solution is to not use typedef, or not to put it inside class B. But what if it belongs in B and I want not to pollute my project's namespace, as in B::SomeTypedef is a more appropriate name than SomeTypedef?
Your design is questionable, although perhaps nested classes is what you intend:
class B {
public:
typedef int SomeTypedef;
private:
class A {
void Foo(SomeTypedef);
};
A a;
};
If not, this can also be solved with another class which is common in CRTP code.
template<typename T>
struct foo;
class A;
class B;
template<>
struct foo<B> {
typedef int SomeTypedef;
};
class A {
void Foo(foo<B>::SomeTypedef);
};
class B : foo<B> {
private:
A a;
};
Or you can use another namespace.
Another method is use an intermediate class, plus pointers, its more long, but, it works:
This is header file, ( yes I know, "*.hpp" extension is not standard ):
ForwardClassExample.hpp
class ForwardClass {
public:
virtual void DoSomething();
};
class ContainerClass {
ForwardClass* Item;
/* constructor */ ContainerClass();
/* destructor */ ~ContainerClass();
};
class RealClass: ForwardClass {
/* override */ virtual void DoSomething();
};
This is body file:
ForwardClassExample.cpp
/* constructor */ ContainerClass::ContainerClass()
{
// create reference to forwaded class item
this.Item = new RealClass();
}
/* destructor */ ContainerClass::~ContainerClass()
{
// deletereference to forwaded class item
free this.Item();
}
void ForwardClass::DoSomething()
{
// ...
}
void RealClass::DoSomething()
{
// ...
}
Note:
I suggest to get used to apply pointers to variables, instead of direct fields, its may looks more difficult, at start, but, eventually allows to do more stuff.
It also prepare you to use "references" in case, one day you have to work with other programming languages.
Cheers.
Introduce the typedef where your design requires it, and then export it to wherever it makes the most sense for your user.
class A
{
public:
typedef int SomeTypedef;
void Foo(SomeTypedef);
};
class B
{
public:
typedef A::SomeTypedef SomeTypedef;
private:
A a;
};