Is there a convenient way to initialize simple structs in C++? - c++

Let's say I have a simple struct like this:
struct Simple
{
int weight;
std::string name;
float power;
};
I'd like to be able to initialize one of these without creating a constructor for it and without having to individually set its parameters. I dream of a syntax like this, for example:
Simple s( 4, "bill", 3.1f );
...or perhaps...
Simple s = { 4, "bill", 3.1f };
...or verily...
Simple s{ 4, "bill", 3.1f };
I know that I can get the first example to work by adding a braindead constructor of my own. Tedious.
Likewise, the last example will work in C++11, but I believe I have to provide the constructor.
Is there a way to simply and elegantly initialize a struct in C++ without having to provide a constructor?

Simple s = { 4, "bill", 3.1f };
Simple s{ 4, "bill", 3.1f };
These are valid.
This syntax will map each value in the above groups/sets to each struct member variable depending on the order and you don't even need to define a constructor.

Related

SFML accessing array inside std::vector

In class A I have:
class A{
A(){};
std::vector<sf::Vertex[2]> lines{ 5 };
};
And I somehow need to access sf::Vertex 0 and 1 of all the line objects in std::vector. The SFML documentation states on lines:
sf::Vertex line[] =
{
sf::Vertex(sf::Vector2f(10, 10)),
sf::Vertex(sf::Vector2f(150, 150))
};
I tried many things, but syntax just doesn't work out, from this:
std::vector lines{ {Vertex(100,100),Vertex( 300,300)},... };
to this:
A(){
lines[0]->sf::Vertex[0] = (100,100);
...};
But it just doesn't work out. What's the proper syntax?
An array is not a valid element type for a vector (or any other standard Container). It doesn't satisfy the requirement of being Erasable. You can instead use a class that has the array as a member. The standard library has a template for such array wrapper: std::vector<std::array<sf::Vertex, 2>>.

C++ data structure where initialization can use its names

I need to create a data structure that has a LOT of members. Example:
struct MyStruct {
int varSomething;
int helloNumber;
int thisIsSomething;
...
int varNumber50;//50th element
}
The problem with this struct is that when I want to instantiate it, I need to do the following:
my_vector[i] = MyStruct{10, 4, 90, ...}
as you can see, I need to put lots of values and I end up confusing which one is which. Ideally, I'd like to do something like this:
my_vector[i] = MyStruct{varSomething = 10, helloNumber = 4, thisIsSomething = 90, ...}
Since each variable has a name, I know what I'm doing, and can't confuse.
I know that I can do this:
MyStruct myStruct;
MyStruct.varSomething = 10;
myStruct.helloNumber = 4;
...
my_vector[i] = myStruct
but I want to create an anonymous struct, it's not nice to create a named struct just to put in the vector.
What should be a great way to solve this problem? Is there something similar to a struct that can achieve what I want??
With c++20 designated initializers you can do the following
struct MyStruct {
int a,b,c;
};
int main(){
MyStruct my_value {
a : 2,
b : 3,
c : 95
};
}
In this case I would recommend against using this as it is a definite code smell.
You need to rethink your design and maybe looking at design patterns like factory, builder or prototype to give you a better idea on how to create your objects.
See the following links for more information:
https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers
https://en.wikipedia.org/wiki/Creational_pattern

Access struct enum from object

I am just learning to use c++ and I'm trying to understand how scope works with classes and embedded enums.
Currently I have a class which looks something like this:
class Foo {
public:
Foo();
enum Option = {
FIRST,
SECOND,
THIRD
};
struct Example = {
const char* name;
Option key;
enum keyOption = {
PROPERTY,
FLAG
} keyValue;
};
};
Then in my main function I initialize it and then add some values to the Example struct
int main()
{
Foo *test;
Foo::Example content = {
"Hello World",
test->FIRST,
test->Example::PROPERTY
};
}
With the above code I will get an error of:
error: 'Foo::keyOption' is not a base of 'Foo'
I know I can fix it by changing test->Example::PROPERTY to Foo::Example::PROPERTY
But is there a way I can access the Example structs values through the object instead of Foo::? Similarly to how I access the FIRST value?
Forgive me if I'm butchering the naming of difference concepts, I'm just trying to teach myself by building something, and I will need to read more into the details soon.
Thank you so much for any help, it is really appreciated!
Foo::FIRST and Foo::Example::PROPERTY are possible values of the enumerator. Only Example::key and Example::keyValue are members of the struct which can be instantiated and initialized to Foo::FIRST and Foo::Example::PROPERTY
This should work
Foo::Example content = {
"Hello World",
test->FIRST,
Foo::Example::PROPERTY
};

C++ Set MIL Question

I am trying to initialize a set with more than one member in my member initialization list and I am not sure about the syntax. The ** is where I am getting my syntax error (without the ** of course). Thanks. Here is an example:
//=============================================================================
class myClass_t
{
//-----------------------------------------------------------------------------
public: // FUNCTIONS
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Constructor
myClass_t
(
)
:
BaseClass_t( IDD_BASEPAGE ),
**mCapabilities( 1, 2 ),
mDevice( mCapabilities )
{
}
//-------------------------------------------------------------------------
// Destructor
~myClass_t
(
)
{
}
//-----------------------------------------------------------------------------
private: // DATA
//-----------------------------------------------------------------------------
fdx::myDevice_t mDevice;
std::set<int> mCapabilities;
}; // end of class
} // end of namespace
If you can use the Boost Assign library, the thing you ask for is easy:
#include <boost/assign/list_of.hpp>
...
mCapabilities(boost::assign::list_of(1)(2))
...
I've just tested it on MSVC8 and it works fine.
There is no such constructor available in set with which you can insert the elements. You need to explictly call set::insert method in the body of the constructor. i.e. you need to do mCapabilities.insert(1);mCapabilities.insert(2);.
The set, like a standard containers, provides a constructor that takes an iterator range as input to construct the collection.
So you cannot directly put the elements that you want to insert into the constructor but you can have a static array and use that to initialise he members:
class myClass_t {
static int const m_init_values[];
static unsigned const m_init_size;
…
};
int const myClass_t::m_init_values[] = { 1, 2 };
unsigned const myClass_t::m_init_size =
sizeof m_init_values / sizeof m_init_values[0];
Note that you need to define the static constant outside of the class, as shown here.
Now you can use these values in your constructor:
myClass_t()
: BaseClass_t(IDD_BASEPAGE)
, mCapabilities(&m_init_values, &m_init_values + m_init_size)
, mDevice( mCapabilities )
{ }
A last remark: your formatting is very space consuming, and consequently requires a lot of scrolling to read the code. You should ask yourself whether the spurious delimiter comments and redundant line breaks really help readability. It’s usually advisable not to have to scroll to read one connected piece of code.
set<int>::set() doesn't accept the arguments you have mentioned. To see the possible ways of constructors, you can refer to the set constructor example.

Populate a static member container in c++

I've got a static class member which is some container, like
(Foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
I need to populate the list with a number of specific values. Actually it should be also const, but that might overcomplicate the problem further.
All the class member functions are static, so initializing it in a constructor doesn't make sense.
a common solution is to do something like this:
// header
class Foo
{
...
private:
static list<string> s_List;
}
// cpp
list<string> init()
{
list<string> tmp;
... fill tmp with strings
return tmp;
}
list<string> Foo::s_List(init());
the other method is like Neil Butterworth suggested.
Another alternative is to create a simple initialiser class:
list <string> Foo::s_List;
struct Init {
Init() {
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
}
};
static Init doInit;
Note that, as the list is private, this will probably require you to make Init a friend of Foo. It's also often convenient to make such classes be contained by the class they are initialising.
However, I just re-read your question and another thought occurs - if the list is const, you will presumably not be changing it, in which case a simple array of strings, initialised with the strings in sorted order may be a better solution. It will certainly be faster to search (using std::binary_search) than a list, and can of course be easily initialised.
If your compiler supports C++0x, this is actually trivial to accomplish.
#include <iostream>
#include <list>
class Foo
{
public:
static std::list<std::string> s_List;
};
std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"};
int main()
{
for(const std::string& str : Foo::s_List)
std::cout << str << std::endl;
return 0;
}
This works for both const and non-const static members. I've tested this snippet with clang-4.2, gcc-4.7, gcc-4.6, and gcc-4.5. Gcc-4.5 does not support the updated for syntax, so you'd have to use a traditional for loop with iterators. Also, don't forget to pass the -std=c++0x flag to the compiler. I'm reasonably confident Visual Studio supports this as well, but I don't know for sure and don't know which versions.
It depends on what values you need to put in that list. Are they static or do they require some form of computation?
If they are static, you can do this:
namespace {
const char* const initVals[] = { "A", "B", "C" };
}
list<string> Foo::s_list(initVals, initVals + 3);
one possible solution would be to use an accessor method that checks to see if it is initialized, and does so if it isn't.
The ways I(the author of the question) have vainly tried to do this.
I tried to do smth like (in Foo.cpp):
list<string> Foo::s_List = list<string>();
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
But that gives a compiler error.
Then I thought of making an Initialize() method and calling it right from the code
void Foo::Initialize()
{
s_List.insert("rats");
s_List.insert("cats");
}
Foo::Initialize();
// error: compiler considers it to be a redefenition of the method, not a call.
The only viable idea left (havent yet tried) would be to check if the list is empty in each method that uses it, and if it's the case, call Initialize(). But that's ugly!