I am following a "Learn OpenGL" book, and it is said that after linking individual shaders and compiling a shader program, we do not need the individual shaders anymore. Although it may be not entirely true in the more complex world of computer graphics, assume it is.
Now, when building the Shader and ShaderProgram classes, I want to implement this "destruct after not needed" behaviour, that is after ShaderProgram constructor finishes its job, vertex and fragment shader objects destructor should be called.
I can easily achieve such by using std::unique_ptr<Shader> and moving it into the ShaderProgram constructor.
I am just curious if there is a way to do it without using std::unique_ptr.
This is the example code I currently have:
class Shader {
public:
Shader(){\\creating a shader}
~Shader(){glDeleteShader(id);}
/* some methods */
private:
unsigned int id;
};
class ShaderProgram {
public:
ShaderProgram(std::unique_ptr<Shader> vertex, std::unique_ptr<Shader> fragment){\\create a shader}
~ShaderProgram(){glDeleteProgram(id);}
/*some methods*/
private:
unsigned int id;
};
Just call glDeleteShader(id) after you link it in your ShaderProgram constructor, no need to define a Shader class to hold this temporary object.
I initialize a static struct in C like that, but in C++ it doesn't want to compile. How do I get the equivalent in C++ that would still be compatible with C? (linux C code that I'm trying to compile on MSVC)
typedef struct float3 {
float x,y,z;
} float3;
void main() {
static float3 value = (float3){ 1.f, 5.f, 10.f };
}
MSVC (visual studio 2019) gives error at the opening bracket '{' after (float3).
Error (active) E0029 expected an expression cpptestvs D:\Projects\cpptestvs\cpptestvs\cpptestvs.cpp 11
Try removing the cast to float3 in the statement enclosed inside void main().
static float3 value = (float3){ 1.f, 5.f, 10.f };
This is a compound literal, which is allowed in C but not C++. C allows you to create an unnamed object of the type float3 and initialise it with an initializer-list. Some compilers, such as GCC, do support it as an extension but MSVC doesn't.
To do what you want you can do:
static float3 value = { 1.f, 5.f, 10.f };
This is aggregate initialisation: every non-static class member in the struct float3 is copy-initialized from the corresponding clause of the initializer list. Your struct is an aggregate because it has no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions.
I want to enhance my AABB class in my raytracer by doing member variable aliasing(make AABB::min alias to AABB::bounds[0] and AABB::max alias to AABB::bounds[1])
This is the current AABB code.
class AABB
{
public:
//methods ignored...
float4 min;
float4 max;
};
To implement class member aliasing. I tried to use union to achieve it. Which makes the declaration of the variables looks like this.
union
{
float4 bounds[2];
struct {float4 min,max;};
};
But this gives me the following error message:
error: member ‘glm::float4 Incarnate::AABB::<anonymous union>::<anonymous struct>::min’ with constructor not allowed in anonymous aggregate
struct {float4 min,max;};
After searching on Google. I don't find any way to workaround this issue while still achieving my original goal of aliasing the variables. (All solutions I found will add complexity on accessing the variables.)
Is there anyway around this?
Note: float4 is glm::vec4. I used the GLM compatibility header so I could program like how I would in OpenCL.
I am being told that I can't use the 'this' keyword in a class function. I'm coming from c# and i'm used to this working, but the compiler tells me that it can only be used within nonstatic member functions.
D3DXVECTOR3 position;
void Position(D3DXVECTOR3 position)
{
this.position = position;
}
this is a pointer containing the address of the object.
D3DXVECTOR3 position;
void YourClassNameHere::Position(D3DXVECTOR3 position)
{
this->position = position;
}
Should work.
D3DXVECTOR3 position;
void YourClassNameHere::Position(D3DXVECTOR3 position)
{
(*this).position = position;
}
Should also work.
In C++ you need to qualify your Position function with the class name:
void YourClassNameHere::Position(D3DXVECTOR3 position)
Also from #Pubby8's answer this is a pointer, not a reference so you need to use this->position instead (or consider using parameter names that don't shadow class members - I like using trailing _ on my class members).
Also, C++ doesn't pass by reference by default so if D3DXVECTOR3 is a complicated type you'll be copying a lot of data around. Consider passing it as const D3DXVECTOR3& position instead.
Not only is Position a free function (not associated with a class) the way you wrote it, but this is also a pointer, not a reference.
D3DXVECTOR3 position;
void ClassName::Position(D3DXVECTOR3 position)
{
this->position = position;
}
or, if that's supposed to be a constructor,
ClassName::ClassName(D3DXVECTOR3 p) : position(p)
{
}
I want to do something like this:
template <typename T:public Vertex> addTri( T v1, T v2, T v3 )
{
// Take v1.pos, v2.pos, v3.pos and create a geometric repn..
Triangle tri( v1.pos, v2.pos, v3.pos ) ; // all vertices will
// have to have a .pos member.
// Create the vertex buffer..
VertexBuffer<T> vb ...
}
Since that doesn't work, this is my workaround..
template <typename T> addTri( T v1, T v2, T v3 )
{
Vertex* p1 = (Vertex*)&v1 ;
// This is a very "shut up C++, I know what I'm doing" type cast.
// I'd like for C++ to know that all vertex types (T in this case)
// __will__ have a Vector member .pos.
Triangle tri( p1->pos, p2->pos, p3->pos ) ;
// Create the vertex buffer..
VertexBuffer<T> vb ...
}
Background
In case you're interested, I'm trying to write a general bit of code to handle triangle creation.
Each vertex has to have a .pos member, because each vertex has to have a position in space.
However not every vertex type will have a texture coordinate. Not every vertex will have a color. Hence the parameterized types.
A similar approach is used in XNA VertexBuffer.SetData<T>.
You cannot specify a type restriction in the template type argument. However, generally, you don't have to.
If you simply do:
template <typename T> addTri( T v1, T v2, T v3 )
{
Vertex &v1r = v1;
// ....
}
This will work if the function is instantiated with a derivative of Vertex. It will create an (obscure) error if T & is not convertible to Vertex &.
If you don't even care if the types are convertible to Vertex as long as they have the same members, you can even skip the assignment - C++ template arguments essentially work using duck typing; if you do v1.x, and T contains a member named x, then it will work, whatever type T might actually be.
You can be a bit more sophisticated using boost's type-traits library and a static assertion; with this, you can start defining an assertion to make the error a bit easier to understand:
template <typename T> addTri( T v1, T v2, T v3 )
{
BOOST_STATIC_ASSERT_MSG(boost::is_convertible<T&, Vertex&>::value,
"Template argument must be a subclass of Vertex");
Vertex &v1r = v1;
// ....
}
A combination of enable_if, is_base_of and is_convertible typetraits should do the job:
template <typename T>
struct Foo : public std::enable_if<std::is_base_of<YourBase, T>::value &&
std::is_convertible<T&, A&>::value,
T>::type
{
// consider "using YourBase::foo;" directives here
};
The type traits are available from <type_traits> in modern compilers, or <tr1/type_traits> or Boost otherwise.
You can do:
#include <type_traits>
template <typename T>
void addTri(T v1, T v2, T v3, char (*)[is_base_of<Vertex, T>::value] = 0)
{
...
}
to disable the generation of addTri if T doesn't inherit from Vertex. But you don't need it to be able to use the pos member.
Update: Actually std::is_base_of will return true if Vertex is an inaccessible base class of T. Use the following implementation of is_base_of instead:
template <typename B, typename D>
struct is_base_of
{
static const bool value = std::is_convertible<D*, B*>::value
&& std::is_class<B>::value;
};
Just use your first solution without the odd :public Vertex. When you instantiate it with a Vertex or with something that just has a pos member, it will be fine. C++ doesn't have to know that every T has a pos member. If you anytime instantiate the template with anything that has no pos member, you will get a compiler error, otherwise it's fine.
What you're looking for is concepts, but they have been dropped from the C++0x standard, I think.
You may be looking at templates wrong. What you describe looks to be handled better by good ole-fashioned inheritance. Instead of passing instances of your object, try passing pointers instead like this:
addTri( Vertex *v1, Vertex *v2, Vertex *v3 )
{
// Take v1.pos, v2.pos, v3.pos and create a geometric repn..
Triangle tri( v1->pos, v2->pos, v3->pos ) ; // all vertices will
// have to have a .pos member.
// Create the vertex buffer..
VertexBuffer<T> vb ...
}
Then just pass pointers to your inheriting objects (casting as the parent class as necessary)