If I have:
Class SomeClass{
private:
int a;
char* name;
public:
SomeClass(int a = 0, char* n = "---"){
...
}
};
Class OtherClass{
private:
SomeClass anArray[100];
int counter;
...
public:
...
};
How do I initialize the array of type SomeClass? As far as I know, when you have a private member that belongs to a user defined class, to initialize it you should include it in the constructor
OtherClass(...):SomeClass(...){
...
}
However, the contents of the array are left for the user to enter, so they are much too unpredictable, and manually entering default values for each field is obviously out of the question.
Given that your SomeClass has a default constructor, you don't need to anything: the default constructor will be call for each if the elements. You want to mention it explicitly can use
OtherClass::OtherClass()
: anArray() {
}
If you want to initialize the sequence of elements with an explicit constructor call with typing it out, you can use a delegating constructor taking a suitably size std::index_sequence<...> and use aggregate initialization of the elements. Here is a complete example of how that would look like:
#include <iterator>
#include <algorithm>
#include <iostream>
struct S {
int value;
S(int value): value(value) {}
};
std::ostream& operator<< (std::ostream& out, S const& s) {
return out << s.value;
}
template <typename S, typename T, std::size_t Size>
constexpr std::size_t static_size(T (S::*)[Size]) {
return Size;
}
class T {
S array[100];
template <std::size_t... I>
T(std::index_sequence<I...>): array{ S(I)... } {}
public:
T(): T(std::make_index_sequence<static_size(&T::array)>()) {}
S const* begin() const { return std::begin(array); }
S const* end() const { return std::end(array); }
};
int main()
{
T t;
std::copy(t.begin(), t.end(), std::ostream_iterator<S>(std::cout, " "));
}
Related
Suppose I have a class in C++11 like this:
class Something
{
...
private:
class1* a;
class2* b;
class3* c;
public:
class1* reada() { return a; }
class2* readb() { return b; }
class3* readc() { return c; }
void customFunctionForclass1();
void customFunctionForclass2();
void customFunctionForclass3();
}
}
I'd like to make the read functions templated so that if another programmer adds another member class, the corresponding read function will be template-magic created.
Something like this maybe?
class Something
{
...
private:
templateContainer = {class1*,class2*,class3*}
template<thing in templateContainer>
thing variableOfTypeThing;
public:
template<thing in templateContainer>
<thing> read() {return variableOfTypeThing<thing>;}
void customFunctionForclass1();
void customFunctionForclass2();
void customFunctionForclass3();
}
As you can tell from the example, I'm confused.
Basically, I have a class which acts as a container for guaranteed unique class variables (no class1 A; class1 B)
Some function groups for the class are almost identical some function groups are highly varied. It would be great for future people to only have to modify the different parts of the class and get the rest from the templates.
I thought maybe there would be a way by splitting this class up into lots of classes and stuffing them into an array of void pointers, but that seems unwise.
Suggestions?
I'd like to make the read functions templated so that if another programmer adds another member class, the corresponding read function will be template-magic created.
You could encapsulate the user defined classes in a thin wrapper class with a read() function that returns the contained instance. Adding a user defined class to Something would then be done by inheriting wrapper<user_defined_class>.
Basically, I have a class which acts as a container for guaranteed unique class variables
Inheriting this wrapper prevents you from including the same class twice so it could possibly be a way forward:
#include <iostream>
// the "thing" wrapper
template<typename T>
struct thing {
// forward construction arguments to the contained variable
template<class... Args>
thing(Args&&... args) : variable(std::forward<Args>(args)...) {}
// basic interface, const and non-const. I called it get() instead of read()
T const& get() const { return variable; }
T& get() { return variable; }
private:
T variable;
};
// a troublesome user defined class that is not default constructibe :-(
struct user_defined {
user_defined() = delete; // silly example really, but it's just to demonstrate
user_defined(const std::string& v) : str(v) {}
user_defined& operator=(const std::string& v) {
str = v;
return *this;
}
std::string const& say() const { return str; }
private:
std::string str;
};
std::ostream& operator<<(std::ostream& os, const user_defined& ud) {
return os << ud.say();
}
// ... and the "Something" class that inherits the wrapped types.
class Something : thing<int>,
thing<double>,
thing<user_defined>
{
public:
// add initial values for types that are not default constructible
Something(const std::string& val) : thing<user_defined>(val) {}
Something() : Something("") {} // default ctor
// access via derived class, const and non-const
template<typename T>
T const& get() const {
return thing<T>::get(); // get() from the correct base
}
template<typename T>
T& get() {
return thing<T>::get(); // get() from the correct base
}
};
void print(const Something& s) {
// using the const interface
std::cout << s.get<int>() << "\n";
std::cout << s.get<double>() << "\n";
std::cout << s.get<user_defined>() << "\n";
}
int main() {
Something foo;
// using the non-const interface to set
foo.get<int>() = 10;
foo.get<double>() = 3.14159;
foo.get<user_defined>() = "Hello world";
print(foo);
}
Edit: It doesn't fulfill the index part of your question though. You access it using the type you'd like to get() as a tag. You basically build a very rudimentary tuple I guess.
Code based on #Ted Lyngmo's answer:
#include <iostream>
#include <string>
template<typename T>
struct thing {
// forward construction arguments to the contained variable
template<class... Args>
thing(Args&&... args) : variable(std::forward<Args>(args)...) {}
// basic interface, const and non-const. I called it get() instead of read()
T const& get() const { return variable; }
T& get() { return variable; }
protected:
T variable;
};
template<typename ...Ts>
struct things : thing<Ts>... {
template<class... SubTs>
things(thing<SubTs>&&... ts) : thing<SubTs>(std::move(ts))... {}
// access via derived class, const and non-const
template<typename T>
T const& get() const {
return thing<T>::get(); // get() from the correct base
}
template<typename T>
T& get() {
return thing<T>::get(); // get() from the correct base
}
};
// a troublesome user defined class that is not default constructibe :-(
struct user_defined {
user_defined() = delete; // silly example really, but it's just to demonstrate
user_defined(const std::string& v) : str(v) {}
user_defined& operator=(const std::string& v) {
str = v;
return *this;
}
std::string const& say() const { return str; }
private:
std::string str;
};
struct non_default {
non_default() = delete;
non_default(int) {}
};
std::ostream& operator<<(std::ostream& os, const user_defined& ud) {
return os << ud.say();
}
// ... and the "Something" class that inherits the wrapped types.
class Something : public things<int, double, user_defined, non_default>
{
public:
// add initial values for types that are not default constructible
Something(const std::string& val) : things(thing<user_defined>(val), thing<non_default>(0)) {}
Something() : Something("") {} // default ctor
};
void print(const Something& s) {
// using the const interface
std::cout << s.get<int>() << "\n";
std::cout << s.get<double>() << "\n";
std::cout << s.get<user_defined>() << "\n";
}
int main() {
Something foo;
// using the non-const interface to set
foo.get<int>() = 10;
foo.get<double>() = 3.14159;
foo.get<user_defined>() = "Hello world";
print(foo);
}
I'm trying to initialize a private member array of a class without using the STL (because it is not supported on the Arduino microcontroller platform I'm using). This means no std::array or std::initializer_list etc.
The following compiles correctly using gcc 5.4.0 and avr-gcc 4.9.2, but that seems to be a bug. Clang throws an error saying error: array initializer must be an initializer list (as expected).
Code
#include <iostream>
#define PRINTFN() std::cout << __PRETTY_FUNCTION__ << std::endl
class Object {
public:
Object(int number) : number(number) { PRINTFN(); }
Object(const Object &o) : number(o.number) { PRINTFN(); }
void print() { std::cout << "The number is " << number << std::endl; }
private:
const int number;
};
template <size_t N>
class ManyObjects {
public:
ManyObjects(const Object(&objects)[N]) : objects(objects) {}
void print() {
for (Object &object : objects)
object.print();
}
private:
Object objects[N];
};
int main() {
ManyObjects<3> many = {{1, 2, 3}};
many.print();
}
Output
Object::Object(int)
Object::Object(int)
Object::Object(int)
Object::Object(const Object&)
Object::Object(const Object&)
Object::Object(const Object&)
The number is 1
The number is 2
The number is 3
What is the proper way to initialize objects? Or is it just not possible with the given constraints?
You can use variadic templates:
In ManyObjects class:
template <typename... _Args>
ManyObjects(_Args&&... arguments) :
objects { arguments... }
{
}
More here
Yes variadic templates work but it is a bit tricky :
template <size_t N>
class ManyObjects {
public:
template<typename T, typename ...Args>
ManyObjects(const T& x, Args&&... args) : objects{x, args...}{}
private:
Object objects[N];
};
int main() {
ManyObjects<3> many{1, 2, 3};
ManyObjects<3> copymany{many};
copymany.print();
}
For any fixed N it can be interpreted as :
template <size_t N=3>
class ManyObjects {
public:
ManyObjects(int x, int y, int z) : objects{x, y, z}{}
...
};
What is at play here :
Object cannot be default initialized due to the definition of the constructor Object(int)
Object assignment operator is implicitly deleted because number is const
Thus any array Object arr[N] must be explicitly initialized using an aggregate initialization.
The only way I think of is to perform extended initialization via the variadic templates.
To prevent matching the copy constructor you can specify the first argument outside the parameter pack. You loose the construction of size 0, which can be enabled with a template specialization.
ManyObjects<0> noneof;
noneof.print();
I ended up following the advice of VTT, and creating my own array wrapper.
I'd love to hear some feedback if there are things that I have to look out for, or possible bugs, etc.
#include <iostream>
class Object {
public:
Object(int number) : number{number} {}
void print() { std::cout << "The number is " << number << std::endl; }
private:
const int number;
};
// -------------------------------------------------------------------------- //
template <class T, size_t N> class ArrayWrapper {
public:
T &operator[](size_t index) { return data[index]; }
const T &operator[](size_t index) const { return data[index]; }
T *begin() { return &data[0]; }
const T *begin() const { return &data[0]; }
T *end() { return &data[N]; }
const T *end() const { return &data[N]; }
T data[N];
};
// -------------------------------------------------------------------------- //
template <size_t N> class ManyObjects {
public:
ManyObjects(const ArrayWrapper<Object, N> &objects, const char *name)
: objects{objects}, name{name} {}
void print() {
std::cout << name << std::endl;
for (auto &object : objects)
object.print();
}
private:
ArrayWrapper<Object, N> objects;
const char *name;
};
// -------------------------------------------------------------------------- //
int main() {
ManyObjects<3> many = {{1, 2, 3}, "Many"};
many.print();
}
I was wondering what is the proper way to initialize a std::array member of the class in the constructor, when the initial array values are parameters to the constructor?
More specifically, consider the following example:
class Car {
public:
Car(const std::string& color, int age): color_(color), age_(age) {}
// ...
private:
std::string color_;
int age_;
};
class ThreeIdenticalCars {
private:
std::array<Car, 3> list;
public:
ThreeIdenticalCars(const std::string& color, int age):
// What to put here to initialize list to 3 identical Car(color,age) objects?
{}
};
Obviously one way is to write list({Car(color,age), Car(color,age), Car(color,age)}), but this clearly does not scale if we wanted 30 identical cars instead of three.
If instead of std::array I used std::vector the solution would have been list(3, Car(color,age) (or list(30, Car(color, age)) but as in my problem the size of the list is known, I thought it is more correct to use std:array.
One option for the array version is to use a template function to build the array. You'll have to test to see if this gets optimized out or copied in release mode,
#include <iostream>
#include <array>
#include <tuple>
class Car {
public:
Car(const std::string& color, int age): color_(color), age_(age) {}
// ...
//private:
std::string color_;
int age_;
};
template <typename CarType, typename... Args ,size_t... Is>
std::array<CarType,sizeof...(Is)> make_cars(std::index_sequence<Is...>,Args&&... args )
{
return { (Is,CarType(args...))... };
}
class ThreeIdenticalCars {
//private:
public:
std::array<Car, 3> list;
//public:
ThreeIdenticalCars(const std::string& color, int age) :
list(make_cars<decltype(list)::value_type>(
std::make_index_sequence<std::tuple_size<decltype(list)>::value>(),
color,
age
))
{}
};
int main()
{
ThreeIdenticalCars threecars("red", 10);
for(auto& car : threecars.list)
std::cout << car.color_ << " " << car.age_ << std::endl;
return 0;
}
Demo
Great answer by rmawatson.
Here's a similar alternative which attempts 2 enhancements:
Construction by model.
copy the model N-1 times and move the last one into place.
Of course it requires that a Car is copy-constructible.
#include <array>
#include <string>
class Car {
public:
Car(const std::string& color, int age): color_(color), age_(age) {}
// ...
private:
std::string color_;
int age_;
};
namespace detail
{
template<std::size_t...Is, class Model>
auto build_array_impl(std::index_sequence<Is...>, Model&& model)
{
constexpr auto size = sizeof...(Is) + 1;
return std::array<std::decay_t<Model>, size>
{
// N-1 copies
(Is, model)...,
// followed by perfect forwarding for the last one
std::forward<Model>(model)
};
}
}
template<std::size_t N, class Type>
auto build_array(std::integral_constant<std::size_t, N>, Type&& model)
{
return detail::build_array_impl(std::make_index_sequence<N-1>(),
std::forward<Type>(model));
}
class ThreeIdenticalCars {
private:
static constexpr auto num_cars = std::size_t(3);
static constexpr auto num_cars_c = std::integral_constant<std::size_t, num_cars>();
std::array<Car, num_cars> list;
public:
ThreeIdenticalCars(const std::string& color, int age)
: list(build_array(num_cars_c, Car(color, age)))
{}
};
int main()
{
ThreeIdenticalCars tic("red", 1);
}
std::vector can be initialized as
std::vector<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
Reference
Now if want to achieve the similar functionality for one of my types, how do I go about doing it? How should I implement the constructor for this functionality?.
How does the standard support me achieving this (reference to standard will be most helpful)?. Basically, if you could teach me how it's implemented for std::vector it will be sufficient.
Can this also be done prior to C++11?
Also, can I have a POD struct type initializer list so that I can have values with different types to initialise my type?
Create a constructor which takes a std::initializer_list as a parameter:
#include <vector>
#include <initializer_list>
template <typename T>
struct foo
{
private:
std::vector<T> vec;
public:
foo(std::initializer_list<T> init)
: vec(init)
{ }
};
int main()
{
foo<int> f {1, 2, 3, 4, 5};
}
std::vector does this is almost exactly the same way (although utilizing begin() and end() - std::initializer_list has iterators much the same way as other containers do). From gcc:
vector(initializer_list<value_type> __l,
const allocator_type& __a = allocator_type())
: _Base(__a)
{
_M_range_initialize(__l.begin(), __l.end(),
random_access_iterator_tag());
}
Edit: I'm not 100% what you're trying to do, but you may simply be able to use uniform initialization to get what you want:
struct bar
{
private:
int i;
double j;
std::string k;
public:
bar(int i_, double j_, const std::string& k_)
: i(i_), j(j_), k(k_)
{ }
};
int main()
{
bar b {1, 2.0, "hi"};
}
I guess if you want a custom initializer list, the following should suffice?
template <typename T>
class Initializer
{
private:
T* _List;
size_t len;
public:
Initializer()
: _List(nullptr), len(0) {}
template <typename... _Rest>
Initializer(T _first, _Rest... _rest)
: _List(new T[sizeof...(_rest) + 1]{_first, _rest...}),
len(sizeof...(_rest) + 1) {}
Initializer<T>& operator=(Initializer<T> &&) = delete; // move operator [Implement your own if you want.]
Initializer<T>& operator=(const Initializer<T>& ) = delete; // copy operator [Implement your own if you want.]
const T operator[] (size_t index) const noexcept
{ return _List[index]; }
T& operator[] (size_t index) noexcept
{ return _List[index]; }
const T* begin() const noexcept
{ return _List; }
T* begin() noexcept
{ return _List; }
const T* end() const noexcept
{ return &_List[len]; }
T* end() noexcept
{ return &_List[len]; }
size_t length() const noexcept
{ return len; }
~Initializer() noexcept
{ _List != nullptr ? delete[] _List : void(0); }
};
Examples:
Passing it as a function constructor:
void func(Initializer<int> list)
{
// Nothing. Absolutely nothing...
}
int main()
{
func({ 104, 101, 108, 108, 111}); // Don't translate to ASCII ;)
}
Initializing it normally:
Initializer<const char*> AListOfStrings = {
"This is a test",
"Mic testing 123",
"Oh good it works!"
};
Now I don't know if there are any edge cases to this way, but if there are you could perhaps let me know about it in the comments and i could try to fix it.
Anyway I think this should be ok.
If someone is still seeking to get yet another answer for this question then you can get the benefit from typeid like:
template <typename Type>
void check_type( Type par ){
if( typeid(Type) == typeid(std::string()) ) {} //check for string type
if( typeid(Type) == typeid(int) ){} //is int
}
So I can't use initializers in my class constructor because of using arrays, so I decided to use an init() method instead. Now I have a different problem. I have a class like this:
class EPWM {
private:
volatile EPWM_REGS* const regs;
public:
void init(volatile EPWM_REGS* _regs);
};
where I need to implement init() by initializing regs = _regs; but I can't because of the const. Is there a way to force the assignment in my init method? I would like to keep the const keyword so I don't accidentally reassign elsewhere.
edit: as much as I would like to use a constructor + initializer, which would solve this problem (my code used to do this), I cannot because I have another class which has an array of EPWM objects, and I can't initialize those objects because C++ does not support initializers for array members. (again, see the other question I asked a little while ago on this subject.)
Context for using EPWM is something like this:
class PwmGroup {
private:
EPWM *epwm;
void init(EPWM *_epwm) { epwm = _epwm; }
};
/* ... */
// main code:
EPWM epwm[3];
PwmGroup pwmGroup;
{
// EPwm1Regs, EPwm2Regs, EPwm3Regs are structs
// defined by TI's include files for this processor
epwm[0].init(&EPwm1Regs);
epwm[1].init(&EPwm2Regs);
epwm[2].init(&EPwm3Regs);
pwmGroup.init(epwm);
}
You could consider const_cast and pointers, but it's something best used very rarely. Something like...
EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(®s);
*regsPP = _regs;
How about the following?
struct EPWM_array {
EPWM_array() { /* initialize array */ }
const EPWM *begin() const;
const EPWM *end() const;
EPWM array[ 10 ];
};
struct EPWMWrapper {
volatile EPWM_REGS* const regs;
EPWMWrapper(EPWM_array const& a) : regs(a.begin()) {}
};
Would something like this help? You can still intentionally violate the constness but it prevents normal people from silly mistakes (I haven't compiled this).
class EPWM {
private:
volatile EPWM_REGS* regs_for_init_never_use;
volatile EPWM_REGS* const& regs;
public:
EPWM() : regs(regs_for_init_never_use)
void init(volatile EPWM_REGS* _regs);
};
Playing devil's advocate: apart from the obvious documentation intent, since it's a private attribute, you could perfectly not use the const keyword and not modify it apart from the init method.
Your const_cast might actually be undefined behavior here, and I certainly prefer not to run in those dark corners, whatever the workarounds.
class EPWM {
private:
volatile EPWM_REGS* regs; // normally const, but need to be inited :/
public:
void init(volatile EPWM_REGS* _regs);
};
Although, revisit your question: while a raw array cannot be default constructed, you can write an array class that can be.
namespace detail
{
template <class T, size_t N, size_t index>
struct At
{
static T& Do(Array<T,N>& array)
{
return At<T,N-1,index-1>::Do(array.tail());
}
};
template <class T, size_t N>
struct At<T,N,0>
{
static T& Do(Array<T,N>& array) { return array[0]; }
};
template <class T, size_t index>
struct At<T,0,index> {};
template <class T>
struct At<T,0,0> {};
} // namespace detail
template <class T, size_t N>
class array
{
public:
typedef T value_type;
static const size_t Length = N;
array(): mHead(), mTail() {}
array(const array& rhs): mHead(rhs.mHead), mTail(rhs.mTail) {}
// Don't know whether it will be optimized or not
// Not sure I can use pointer arithmetic either :p
T& operator[](size_t index) { return index == 0 ? mHead : mTail[index-1]; }
// Compile time access
template <size_t index>
T& at() { return detail::At< T, N, index >::Do(*this); }
private:
T mHead;
array<T, N-1> mTail;
}; // class array<T,N>
template <class T>
class array<T,1>
{
public:
typedef T value_type;
static const size_t Length = 1;
array(): mHead() {}
array(const array& rhs): mHead(rhs.mHead) {}
T& operator[](size_t index) { return mHead; } // or error handling ;)
private:
T mHead;
}; // class array<T,1>
template <class T> class array<T,0> {}; // int[0] does not work (stack) so...
Okay... perhaps not as efficient as a real array... you can always turn to Preprocessor generation though:
template <class T>
class Array4
{
public:
Array4(): m0(), m1(), m2(), m3() {}
Array4(const Array4& rhs): m0(rhs.m0), m1(rhs.m1), m2(rhs.m2), m3(rhs.m3) {}
T& operator[](size_t index) { return *(&m0 + index); }
private:
T m0;
T m1;
T m2;
T m3;
}; // class Array4<T>
Use a constructor like this:
EPWM::EPWM(volatile EPWM_REGS* _regs)
: regs(_regs)
{}
Then simply have no params in init:
void EPWM::init()
{
// do something with this->regs here...
}
In other words, you can initialise everything in the class constructor - just not member arrays.