I just started learning more of c++ and am writing a small rendering engine as an example case study. As i started to implement more code I got annoyed by typing types like
std::vector<std::vector<int>>
over and over again. As most of you know already, this get's infinitely worse if you are looping over said vector
for (std::vector<std::vector<Tile>>::const_iterator layerRow = ...) {}
Since this is not just annoying but also very error prone, I looked into using typedefs and soon changed those into alias', following Scott Meyers advice in "More effective C++".
I got one problem now which I can't seem to wrap my head around. Given the following two files (corresponding header and source file):
map.h:
class Map
{
public:
using tileLayerVector_t = std::vector<std::vector<Tile>>;
using rawDataLayerVector_t = std::vector<std::vector<int>>;
tileLayerVector_t getTileLayer(const std::string pLayerName) const;
void generateTileMapLayer(const std::string pMapLayerName, const rawDataLayerVector_t pRawMapData, const std::shared_ptr<Texture> pTexture);
}
map.cpp:
#include <map.h>
tileLayerVector_t Map::getTileLayer(const std::string pLayerName) const
{
return mapLayers.at(pLayerName);
}
void Map::generateTileMapLayer(const std::string pMapLayerName, const
rawDataLayerVector_t pRawMapData, const std::shared_ptr<Texture> pTexture)
{
int tileCount = 0;
int xPos = 0;
int yPos = 0;
...
std::pair<std::string, tileLayerVector_t> tileLayer(pMapLayerName, tileMapLayer);
mapLayers.insert(tileLayer);
}
Function generateTileMapLayer() compiles fine without a problem. As soon as I implement getTileLayer() the UI is giving me an error "identifier 'tileLayerVector_t' is undefined" and the compiler is giving me some weird error about a missing ";" somewhere. This compiler error vanishes if I put getTileLayer() in comments.
I don't understand why I can use the alias within the function generateTileMapLayer() as a type definition for the hash map, but cannot use it as a return type for getTileLayer(). I put Map::tileLayerVector_t as a return type and it works. Why does it work without the namespace within generateTileMapLayer() though?
Maybe someone can help me with this. Thank you in advance!
A class defines a scope. How you access something in a given scope depends on whether you are writing code that's inside or outside that scope.
So when you make the declaration using tileLayerVector_t = ...; within class Map you are providing an alias for a new type Map::tileLayerVector.
This is why your code inside the class can use the type without qualification, but code outside cannot.
You could move your using-declarations outside the class, but that would pollute the global namespace. A better solution, I think, would be to simply qualify the types where needed:
Map::tileLayerVector_t Map::getTileLayer(...) // must qualify type here
{
tileLayerVector_t temp = ...; // inside a class method, no problem here
}
A more modern solution would be to use "type inference". I believe you need at least a C++11 compliant compiler to take advantage of this feature. My understanding is that the trailing return type allows the compiler to defer establishing the actual type until after the function signature has been generated, at which point the scope has been established.
auto Map::getTileLayer(...) -> tileLayerVector_t
{
....
}
Related
In a class header file Texture.h I declare a static const int.
static const int MAX_TEXTURE_SLOTS;
In Texture.cpp I define the variable as 0.
const int Texture::MAX_TEXTURE_SLOTS = 0;
Now in Window.cpp class's constructor I attempt to assign to the variable using an out parameter, however this obviously does not compile as &Texture::MAX_TEXTURE_SLOTS points to a const int* and not an int* .
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &Texture::MAX_TEXTURE_SLOTS);
I have tried using const_cast, but am greeted with a segmentation fault on runtime.
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, const_cast<int*>(&Texture::MAX_TEXTURE_SLOTS));
I have also tried directly casting to an int * but once again, seg fault.
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (int*)&Texture::MAX_TEXTURE_SLOTS);
Many thanks.
EDIT 2: So since you're trying to abstract OpenGL contexts, you'll have to let go of the "traditional" constructor/destructor idioms. And just for your information (unrelated to this question): OpenGL contexts are not tied to windows! As long as a set of windows and OpenGL contexts are compatible with each other, you may mix and match any way you like. But I digress.
The standard idiom to deal with a situation like yours is to use preinitializing factory functions. Like this:
class MyOpenGLContextWrapper {
public:
// Yes, shared_ptr; using a unique_ptr here for objects that are kind
// of a nexus for other things -- like an OpenGL context -- just creates
// a lot of pain and misery. Trust me, I know what I'm talkink about.
typedef std::shared_ptr<MyOpenGLContextWrapper> ptr;
struct constdata {
NativeGLContextType context;
// ...
GLint max_texture_image_units;
// ...
};
static ptr create();
protected:
MyOpenGLContextWrapper(constdata const &cdata) : c(cdata) {};
virtual ~MyOpenGLContextWrapper();
constdata const c;
}
MyOpenGLContextWrapper::ptr MyOpenGLContextWrapper::create()
{
struct object : public MyOpenGLContextWrapper {
object(MyOpenGLContextWrapper::constdata const &cdata) : MyOpenGLContextWrapper(cdata) {}
~object(){}
};
MyOpenGLContextWrapper::constdata cdata = {};
// of course this should all also do error checking and failure rollbacks
cdata.context = create_opengl_context();
bind_opengl_context(cdata.context);
// ...
glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS, &cdata.max_texture_image_units);
return std::make_shared<object>(cdata);
}
EDIT: I just saw that you intend to use this to hold on to a OpenGL limit. In that case you can't do this on a global scope anyway, since those values depend on the OpenGL context in use. A process may have several OpenGL contexts, each with different limits.
On most computer systems you'll encounter these days, variables declared const in global scope will be placed in memory that has been marked as read only. You literally can't assign to such a variable.
The usual approach to implement global scope runtime constants is by means of query functions that will return from an internal or otherwise concealed or protected value. Like
// header.h
int runtime_constant();
#define RUNTIME_CONSTANT runtime_constant()
// implementation.c / .cpp
int runtime_constant_query(){
static int x = 0;
// NOTE: This is not thread safe!
if( !x ){ x = determine_value(); }
return x;
}
You can then fetch the value by calling that function.
Provided that glGetIntegerv doesn't depend on other gl* functions being called before, you may use an immediately-invoked lambda:
// Texture.cpp
const int Texture::MAX_TEXTURE_SLOTS = []
{
int maxTextureSlots{0}:
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureSlots);
return maxTextureSlots;
}();
You don't.
You can't assign to a const outside of its definition. Also, using a const variable where the const has been const_casted away is UB. This also means you can't directly initialize a const variable with an output parameter. For trivial types, just output to another variable and make a const copy if you so wish.
If you were the author of the function you're calling, you would do well not to use out parameters, and then you could assign to const variables directly, perhaps using structured bindings if you want to name multiple of the outputs at a time. But here, you're not.
In every lesson and book on C++ I've ever seen, a class has been written like this:
header.h
class MyClass
{
...
int myMethod(int my_para);
};
source.cpp
...
int
MyClass::myMethod(int my_para)
{
...
}
But I do find that the MyClass:: just adds to the natural chaos and bewilderment of C++, especially when MyClass is actually more like MySomethingSomethingCreator. I would like to write my class definitions in more of a namespace style, like this:
header.h
class MyClass
{
...
int myMethod(int my_para);
};
source.cpp
class MyClass
{
...
int myMethod(int my_para)
{
...
}
}
Now, I know from trying that doing exactly this does not work, but is there a way to do something similar - just to remove a little of the noise? I am not interested in defining functions actually inside the class declaration - that's the work of the devil!
but is there a way to do something similar
No.
MyClass:: just adds to the natural chaos and bewilderment of C++
It's just one of the little things that a new C++ programmer has to learn to accept. Once you get used to it, it will no longer be bewildering.
MyClass:: just adds to the natural chaos and bewilderment of C++
I wouldn't agree with you. Imagine you are working with a huge code database, and you come across a definition of a function in .cpp file like this.
.
.
.
.
int myfunc(std::string some_arg)
{
//whatever can be here
}
.
.
.
.
.
And now you would wonder, is this a function in a namespace or method of some class. Of course the class specifier you suggested would appear above, but in can be thousand of lines above, or even 10 thousands, which one probably wouldn't want to deal with. Someone would like to know if it is a method or function by directly looking on it.
The MyClass:: specifier serves greatly for this purpose.
You cannot. This is generally not a problem, though. In fact, there is good reason to want to do this with free functions. John Lakos points out in Large-Scale C++ Volume I (2020) p. 155–156, you can (and may want to) do this:
// foo.h
namespace my_product {
int foo(int);
} // namespace my_product
then
// foo.cpp
#include <my_product/foo.h>
int my_product::foo(int x) {
return x * 2;
}
The advantage of this is: suppose you want to change the signature to take float and you change it in the .cpp to float my_product::foo(float x). If done this way, float my_product::foo(float x) can only define the function, it can't declare it, so you'd get a compile error: https://godbolt.org/z/eGbv3rTx5
error: out-of-line definition of 'foo' does not match any declaration in namespace 'my_product'
float my_product::foo(float x) {
^~~
whereas if your .cpp file is
// foo.cpp
#include <my_product/foo.h>
namespace my_product {
float foo(float x) {
return x * 2;
}
} // namespace my_product
and you try to use the function, you have to wait for the whole project to build and then get a link error: https://godbolt.org/z/soo7r97fG
undefined reference to `my_product::foo(int)'
I've started to get in this habit of defining functions like this so I can have immediate compile errors rather than waiting for a potentially big build only to get a link error, which then requires fixing the header (hopefully correctly!) and then waiting again for a big rebuild.
I'm learning C++ using Xcode and have written several small programs including a hangman game but I'm having trouble every time I try to separate a class into definition and implementation. I made a simple case that shows my problem. Short version is it seems that I need to specify a type in the implementation file even though it is already defined in the header file. I get "C++ requires a type specifier for all declarations" on lines 12 and 13 in my example. But if I change line 12, for example, to
int xmlelem::atrb_count = 0;
it gets the error "non-static data member defined out-of-line". In other cases I have got an error saying that I was trying to redefine something. I think I'm missing a fundamental concept somewhere. I did not see this particular issue in the handful of similar questions I looked at.
xmlelem.hpp
// xmlelem.hpp
// learn header
//
//
#ifndef xmlelem_hpp
#define xmlelem_hpp
#include <stdio.h>
#include <string>
#endif /* xmlelem_hpp */
class xmlelem {
private:
int atrb_count;
std::string tag_name;
public:
xmlelem(std::string tag);
void add_atrib();
std::string output();
};
xmlelem.cpp
// xmlelem.cpp
// learn header
//.
//
#include "xmlelem.hpp"
#include "string"
#include <iostream>
// line 11
xmlelem::atrb_count = 0;
xmlelem::tag_name = "";
xmlelem::xmlelem(std::string tag){
tag_name = tag;
}
void xmlelem::add_atrib(){
atrb_count++;
}
std::string xmlelem::output(){
std::string build = "<";
build = build + tag_name + " " + std::to_string(atrb_count);
build = build + ">";
return build;
}
and main.cpp
// main.cpp
// learn header
//
//
#include <iostream>
#include "xmlelem.hpp"
using namespace std;
int main(){
xmlelem clip("test)");
std::cout << clip.output() << " test \n";
}
Let's take a look at the (second) error message.
non-static data member defined out-of-line
There are two parts to the error: "non-static data member" and "defined out-of-line". These are incompatible, so one of them must be changed. Furthermore, only one of them should be changed, or else you may run into a different problem. Decide which of the two parts is correct for your situation.
Keep "defined out-of-line"
When the line
int xmlelem::atrb_count = 0;
is encountered at namespace scope (that is, in neither a function nor a class/struct/union definition), it is an out-of-line definition. This definition tells the compiler to reserve, right at that spot, enough space for an int. Then whenever any xmlelem object accesses the atrb_count member, it will access this particular space. So there is one int shared by all objects.
However, this behavior corresponds to a static member. To make the declaration agree with the implementation, the keyword static needs to be added.
class xmlelem {
private:
static int atrb_count;
/* rest of the class definition */
};
Keep "non-static"
A non-static data member is stored inside each object of the class. Each object can do what it wants with its copy of the data without impacting other objects. So telling the compiler to reserve space outside the objects is contradictory. Simply removing the out-of-line definition is enough to get rid of the error message, but presumably you wanted that initialization to occur somewhere, right?
The initialization of non-static data members can be done either in-line or in a constructor. An example of moving the initialization in-line is the following.
class xmlelem {
private:
int atrb_count = 0;
/* rest of the class definition */
};
This is sometimes reasonable, but the stated goal was to separate the interface from the implementation. Therefore, it might be undesirable for the initial value of 0 to appear in the header file, as it does in the above. The alternative is to move the initial value to the constructor (to each constructor, if you had more than one).
xmlelem::xmlelem(std::string tag) :
atrb_count(0),
tag_name(tag)
{
}
(I've also taken the liberty of moving the initialization of tag_name into the initialization list.)
Remember, if you have more than one constructor, this needs to be done in each constructor that actually utilizes the default value (for an exception, think "copy constructor"). Repeated code is a drawback; it is up to you to decide if the gains are worth the cost.
Remember that you are declaring a class. A class is an abstract concept. When you do this xlemem::atrb_count = 0;, you are having a concrete value on an abstract concept. Doesn't make sense, right? You don't think of a particular color when you think of the general concept of dog. Any initiliazations should be done inside the constructor, because only in the constructor is that we create a concrete object.
Therefore, you should eliminate lines 11 and 12 where you initialize these 2 attributes and your constructor code should be changed to:
xmlelem::xmlelem(std::string tag){
tag_name = tag;
atrb_count = 0;
}
Note that it isn't necessary to initialize a string to "".
Below code came from a post about C++ interview questions here. I've never known this technique :) (though it's claimed a good one :)). My questions are: In which situation do we need to use it? Do you often see it in your real production/legacy code?
Question:
Implement a method to get topSecretValue for any given Something* object. The method should be cross-platform compatible and not depend on sizeof (int, bool, string).
class Something {
Something() {
topSecretValue = 42;
}
bool somePublicBool;
int somePublicInt;
std::string somePublicString;
private:
int topSecretValue;
};
Answer:
Create another class which has all the members of Something in the same order, but has additional public method which returns the value. Your replica Something class should look like:
class SomethingReplica {
public:
int getTopSecretValue() { return topSecretValue; } // <-- new member function
bool somePublicBool;
int somePublicInt;
std::string somePublicString;
private:
int topSecretValue;
};
int main(int argc, const char * argv[]) {
Something a;
SomethingReplica* b = reinterpret_cast<SomethingReplica*>(&a);
std::cout << b->getTopSecretValue();
}
It’s important to avoid code like this in a final product, but it’s nevertheless a good technique when dealing with legacy code, as it can be used to extract intermediate calculation values from a library class. (Note: If it turns out that the alignment of the external library is mismatched to your code, you can resolve this using #pragma pack.)
You can do this without reinterpret_cast. There is a trick using templates and friends that is outlined in the following blog post that demonstrates the technique:
Access to private members. That's easy!
This is certainly safer than the interviewer's approach, since it eliminates human error in re-creating the class definition. Is this approach good at all, though? The given question has some incredibly artificial constraints that would rarely apply to a 'real' project. If it's a C++ project and you have access to the header file, why not just add a getter? If it's not a C++ project, why are you so constrained in your definition of the interop class?
I have the following class with a method signature as below:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
In the implementation file, I've got this:
std::vector<std::string> Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
So I thought to myself, let's see if I can simplify this function signature a bit with some auto-magic as it's getting to be a "bit of a line-full"! So I tried this...
class Foo
{
public:
auto barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
auto Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Now ignoring the fact that, yes I can use a "using namespace std", to trim it down a lot, I was wondering why the compiler gave me an error "a function that returns 'auto' cannot be used before it is defined".
I personally would have thought the compiler would have easily been able to deduce the return type of the method, but in this case it doesn't seem so. Sure, you can fix it with a trailing return type as below:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&) -> std::vector<std::string>;
}
But then if you use the above, it's no better than it was before. So, apart from "using namespace std", is there a nicer way to do the above, and why can't the compiler deduce the return-type in this instance? Or even, does it depend on how this method is invoked that's causing the compiler not to be able to figure out the return type.
The issue here is an issue of how include files work. Your error:
a function that returns 'auto' cannot be used before it is defined
means that in the file you are using your function, its definition (ie. implementation) not anywhere in the file before the usage. This means that the compiler compiling your code using the function can't deduce the functions return type, as that requires access to the definition (implementation). The most likely reason for this is that the function's definition (implementation) is in its own source (.cpp, .c, etc.) file, that is not included. To more fully understand this, I recommend reading this answer, and perhaps this answer as well.
To address the titular question, likely the easiest way to shorten that signature is with a typedef. More specifically, you can add the following code wherever you see appropriate, provided the scoping is appropriate (I would add it as a public member in your class):
typedef std::vector<std::string> strvec;
This allows you to re-write your method signature as the much more manageable:
strvec barreuslts(const strvec&, const strvec&)
When sticking to C++11, you can't rely on deduced return types, you need the trailing return type (C++14 allows that, though). As there is nothing special about the trailing return type in your case, i.e., no expression is passed decltype to determine the return type, I would instead try to shorten the method signature with some type aliases:
class Foo
{
public:
using StrVec = std::vector<std::string>;
StrVec barResults(const StrVec&, const StrVec&);
};
Foo::StrVec Foo::barResults(const StrVec& list1, const StrVec& list2)
{
StrVec results;
// small amount of implementation here...
return results;
}
If you are just looking for a visually appealing way to deal with longer signatures, stop forcing everything to be on one line. Be liberal with your vertical spacing and insert line breaks. The signature contains quality information for the caller and what you may be looking for is a multi-line signature. If you are working with 80 character page widths, reconsider the indentation on the access specifier.
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&,
const std::vector<std::string>&);
}
std::vector<std::string>
Foo::barResults(const std::vector<std::string>& list1,
const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
There are many styles when it comes to splitting up a declaration. Having a tool like clang-format in your toolset will do this automatically and consistently for you.