I'm working on legacy code which looks like the following:
class Foo {
public:
Foo();
private:
bool a1, a2, a3 /*, ...*/, a50;
};
Foo::Foo() {
a1 = a2 = a3 /* = ... */ = a50 = false;
}
This is messy. Is there a way to default all private variables of the same time to a single value that's different from the above? I don't want to use an initializer list because there are so many variables.
I know the default constructor of bool assigns false - can this be leveraged?
There are many possible ways to do it, but all of them are very similar. Anyway you will assign each your variable using different forms.
The main method which I think the best is right assign all variables at your constructor line by line. May be its not compact, but it the most meaningful and you allways can easy look your variables default value:
Foo::Foo() {
a1 = false;
a2 = false;
/*...*/
a50 = false;
}
Another method is which you described, with assign operators:
Foo::Foo() {
a1 = a2 = a3 /* = ... */ = a50 = false;
}
And another one allows initialize variables right after constructor declaration:
Foo::Foo() :
a1(false),
a2(false),
/*...*/
a50(true)
{ }
If I forget any method write it to comments, please.
class Foo
{
private:
bool a1{}, a2{}, /*...,*/ a50{};
};
try with this
Foo::Foo (bool aa) : a1 (aa) , a2 (aa), a3 (aa),/*......*/a50(aa){}
You can have another class (in a separate header) which looks like following.
class myBool {
public:
myBool(int x = 1) { _m = x; }
operator bool() const { return 0 < _m; }
private:
int _m;
};
and in your file you can add following
#include "myBool.h"
#define bool myBool
This will initialize all of bool to default value you set in myBool. You may need to add some more methods to myBool class to use it as a full fledge data type. Above is the bare minimum to explain the answer.
Here is an alternative solution to the ones I've seen posted so far, in case it's useful to you.
Put the data you want to mass-initialize to a default false/0 value in its own struct:
struct MyData
{
bool a, b, c, d;
std::string e, f;
};
Now inherit (privately or otherwise) from this struct, and explicitly initialize it in the constructor's initialization list:
class MyClass : private MyData
{
public:
MyClass()
: MyData()
{
}
};
This sets all the bools to false, the strings are empty, any ints become 0, pointers become null, etc, etc
If you forget to put the struct explicitly in the initialization list, some of its members may be uninitialized.
Confirming that it always requires more work to be lazy in c++...
#include <iostream>
#include <utility>
template<class Tuple, std::size_t...Is>
void zero_out_impl(Tuple& t, std::index_sequence<Is...>)
{
using expand = bool[];
(void) expand { false, (std::get<Is>(t) = false)... };
}
template<class...Args>
void zero_out(std::tuple<Args...> t)
{
zero_out_impl(t, std::index_sequence_for<Args...>());
}
struct lots_of_bools {
lots_of_bools()
{
zero_out(std::tie(a,b,c,d,e,f,g,h,i,j));
}
private:
bool a,b,c,d,e,f,g,h,i,j;
};
auto main() -> int
{
lots_of_bools x;
return 0;
}
Here's another way - wrap the bool in a wrapper that default-constructs it.
#include <iostream>
struct auto_false
{
auto_false(bool initial = false) : value(initial) {};
operator bool() const { return value; }
operator bool& () { return value; }
private:
bool value;
};
struct lots_of_bools {
lots_of_bools()
{
}
bool value_of_f() const {
return f;
}
void set_f(bool val) {
f = val;
}
private:
auto_false a,b,c,d,e,f,g,h,i,j;
};
using namespace std;
auto main() -> int
{
lots_of_bools x;
cout << x.value_of_f() << endl;
x.set_f(true);
cout << x.value_of_f() << endl;
return 0;
}
output:
0
1
Related
I have several classes that each of them has an ID and the Id is passed to the class as a template parameter:
typedef class1<1> baseClass;
typedef class2<2> baseClass;
typedef class<100> baseClass;
Now I need a map so if I can associate 1 with Class1 and 2 with Class2 and so on.
How can I create such vector? I am working on a header only library, so it should be a header only definition.
I am looking something that do the same thing that this code would do (if someone can compile it!):
std::map<int,Type> getMap()
{
std::map<int,Type> output;
output.add(1,class1);
output.add(2,class2);
output.add(100,class100);
}
The idea is that when I get as input 1, I create a class1 and when I receive 2, I create class2.
Any suggestion is very appreciated.
using this data, then I can write a function like this:
void consume(class1 c)
{
// do something interesting with c
}
void consume(class2 c)
{
// do something interesting with c
}
void consume(class3 c)
{
// do something interesting with c
}
void consume(int id,void * buffer)
{
auto map=getMap();
auto data= new map[id](buffer); // assuming that this line create a class based on map, so the map provide the type that it should be created and then this line create that class and pass buffer to it.
consume(data);
}
As a sketch:
class BaseClass { virtual ~BaseClass() = default; };
template<std::size_t I>
class SubClass : public BaseClass {};
namespace detail {
template<std::size_t I>
std::unique_ptr<BaseClass> makeSubClass() { return { new SubClass<I> }; }
template<std::size_t... Is>
std::vector<std::unique_ptr<BaseClass>(*)> makeFactory(std::index_sequence<Is...>)
{ return { makeSubclass<Is>... }; }
}
std::vector<std::unique_ptr<BaseClass>(*)> factory = detail::makeFactory(std::make_index_sequence<100>{});
We populate the vector by expanding a parameter pack, so we don't have to write out all 100 instantiations by hand. This gives you Subclass<0> at factory[0], Subclass<1> at factory[1], etc. up to Subclass<99> at factory[99].
If I understand correctly you want a map to create different types according to a given number.
If that is so, then the code should look something like this:
class Base
{
};
template <int number>
class Type : public Base
{
public:
Type()
{
std::cout << "type is " << number << std::endl;
}
};
using Type1 = Type<1>;
using Type2 = Type<2>;
using Type3 = Type<3>;
using CreateFunction = std::function<Base*()>;
std::map<int, CreateFunction> creators;
int main()
{
creators[1] = []() -> Base* { return new Type1(); };
creators[2] = []() -> Base* { return new Type2(); };
creators[3] = []() -> Base* { return new Type3(); };
std::vector<Base*> vector;
vector.push_back(creators[1]());
vector.push_back(creators[2]());
vector.push_back(creators[3]());
}
output:
type is 1
type is 2
type is 3
If you need only to create object, it would be enough to implement template creator function like:
template<int ID>
Base<ID> Create()
{
return Base<ID>();
}
And then use it:
auto obj1 = Create<1>();
auto obj2 = Create<2>();
// etc
Working example: https://ideone.com/urh7h6
Due to C++ being a statically-typed language, you may choose to either have arbitrary types that do a fixed set of things or have a fixed set of types do arbitrary things, but not both.
Such limitations is embodied by std::function and std::variant. std::function can have arbitrary types call operator() with a fixed signature, and std::variant can have arbitrary functions visit the fixed set of types.
Since you already said the types may be arbitrary, you may only have a fixed set of things you can do with such a type (e.g. consume). The simplest way is to delegate the hard work to std::function
struct Type
{
template<typename T>
Type(T&& t)
: f{[t = std::forward<T>(t)]() mutable { consume(t); }} {}
std::function<void()> f;
};
void consume(Type& t)
{
t.f();
}
What you are looking for is either the Stategy pattern:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class A {
public:
A() {}
virtual void doIt() {};
};
class Aa : public A {
public:
Aa() {}
virtual void doIt() {
std::cout << "do it the Aa way" << std::endl;
}
};
class Ab : public A {
public:
Ab() {}
virtual void doIt() {
std::cout << "do it the Ab way" << std::endl;
}
};
class Concrete {
public:
Concrete(std::string const& type) {
if (type == ("Aa")) {
_a.reset(new Aa());
} else if (type == "Ab") {
_a.reset(new Ab());
}
}
void doIt () const {
_a->doIt();
}
private:
std::unique_ptr<A> _a;
};
int main() {
std::vector<Concrete> vc;
vc.push_back(Concrete("Aa"));
vc.push_back(Concrete("Ab"));
for (auto const& i : vc) {
i.doIt();
}
return 0;
}
Will output:
do it the Aa way
do it the Ab way
I wonder if there is a workaround is such situation:
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
}
//...
A a; //crash
//...
I suppose it is caused by order of initialization. Variable B is initilized by calling an uninitilized std::function instance, hence the crash. By my logic, the workaround would be to initialize std::function first, then initialize member B. But then, such code is not valid:
class A
{
//error: 'B' was not declared in this scope
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
}
I tried to make to make the std::function static, and such code works, but requires non-constexpr/const member, because std::function has non-trivial destructor - which is bad, because that requires source file, which requires creating such file, which requires some efford and destruction of my beautiful header-only class hierarchy! (I mean, I could be lazy and define this variable in the header, but then the multiple definition problem occurs). I know it might be a bad design (i'm just testing things out), but do you have any ideas how the problem can be solved without involving source files?
Although your example is contrived, there are times when I've needed (or its more convenient) to initialize complex objects in a similar way.
But, why use std::function<>? Why not just use a function?
class A
{
class
{
public:
void setValue(int val) { i = val; }
private:
int i;
} B = initB(10);
static decltype(B) initB(int value)
{
decltype(B) temp;
temp.setValue(value);
return temp;
}
};
Although, I wouldn't normally use decltype(B); I would just give the class a name.
I feel like I am somehow subverting your intent, but if you initialize the variables in the constructor, you can make things work.
#include <functional>
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B;
std::function<decltype(B)(int)> initB;
public:
A() {
initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
B = initB(10);
}
};
int main() {
A a;
}
A::initB is a value. It's not initialized at the point where you call it, because initialization is done (loosely speaking) in the order you specify member fields. You can verify this by executing the below, which works:
#include <iostream>
#include <functional>
using namespace std;
template<typename T, typename U>
T set(T& tgt, const U& src)
{
new(&tgt) T(src);
return tgt;
}
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = set(initB, [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;})(10);
std::function<decltype(B)(int)> initB;
};
int main() {
A a;
}
I am looking for an optimal pattern for partial re-initialization of a C++ object.
With partial re-initialization I mean that some members (step_param in the code example) need to keep its values and other members (value in the code example) are re-init'ed.
Important point: The bloat and redundancy of an init() or reset() member function that does basically the same as the constructor should be avoided.
So far I have the following solution:
namespace reinit_example
{
struct reinit_t {} reinit;
struct stepper_t
{
int step_param; // keep parameter
int value;
stepper_t()
: step_param(1)
, value(step_param)
{}
stepper_t( const stepper_t & c, reinit_t )
: step_param(c.step_param)
, value(step_param)
{}
void step()
{
value += step_param;
}
};
void use_cases_1()
{
stepper_t c;
// use c
c.step();
// and later reinit
c = stepper_t(c,reinit);
}
} // namespace
It should also work well with inheritance and composition:
namespace reinit_example
{
struct stepper_2_t : public stepper_t
{
int step_param_2; // keep parameter
int value_2;
public:
stepper_2_t()
: step_param_2(0)
, value_2(step_param_2)
{}
stepper_2_t( const stepper_2_t & cc, reinit_t )
: stepper_t(cc)
, step_param_2(cc.step_param_2)
, value_2(step_param+2)
{}
void step()
{
stepper_t::step();
value_2 += value + step_param_2;
}
};
struct stepper_comp_t
{
stepper_t c;
stepper_2_t cc;
public:
stepper_comp_t()
{}
stepper_comp_t( const stepper_comp_t & d, reinit_t )
: c(d.c,reinit)
, cc(d.cc,reinit)
{}
void step()
{
c.step();
cc.step();
}
};
void use_cases_2()
{
stepper_2_t cc;
// use cc, change config
cc.step();
// maybe change config
cc.step_param = 2;
// reinit
cc = stepper_2_t(cc,reinit);
stepper_comp_t d;
d = stepper_comp_t(d,reinit);
}
} // namespace
C++11 non-static member initialization makes it even simpler:
#if __has_feature(cxx_nonstatic_member_init)
namespace reinit_example
{
struct stepper_11_t
{
int step_param = 0 ; // keep value
int value = step_param;
stepper_11_t()
{}
stepper_11_t( const stepper_11_t & c11, reinit_t )
: step_param(c11.step_param)
{}
};
void use_cases_3()
{
stepper_11_t c11;
c11 = stepper_11_t(c11,reinit);
}
} // namespace
#endif
For testing:
int main()
{
reinit_example::use_cases_1();
reinit_example::use_cases_2();
#if __has_feature(cxx_nonstatic_member_init)
reinit_example::use_cases_3();
#endif
}
Solution proposed by Jerry Coffin: Parameters are moved into a separate struct, which is passed to the constructor to reinit.
namespace reinit_example
{
struct stepper_config_t
{
struct config_t
{
config_t()
: step_param(1)
{}
int step_param;
int other_param;
};
config_t config;
int value;
stepper_config_t()
: value(config.step_param)
{}
stepper_config_t( const config_t & c)
: config(c)
, value(c.step_param)
{}
void step()
{
value += config.step_param;
}
};
void use_cases_4()
{
stepper_config_t c;
// use c
// and later reinit
c = stepper_config_t(c.config);
}
} // namespace
i believe you should be looking for completely different design pattern.
for example, the "keeper" members should form a full-featured class, while the rest of the members that you don't want to keep would be considered a context of this class (would be another class, used to do some operations on the first class).
this is kind of similar to the flyweight design pattern.
For a constructor with multiple arguments...
For example:
class C {
public:
C(int a=1, int b=2){ cout << a << ", " << b << "\n"; }
}
int main(){
C a(10), b = 20;
}
output:
10, 2
20, 2
How do I just assign value to the 2nd parameter? So that I can get "1, 20" without knowing the default values? Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
And how do I implicitly assign all the parameters? If I can't do that, why? For the above example (as I am new to C++), I once thought I would get "10, 20" as output instead.
Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
Yes. Otherwise, how is the compiler supposed to know which argument should be used for which parameter?
However, there are ways to accomplish this. For example,
struct C {
enum { DefaultA = 1, DefaultB = 2 };
C(int a = DefaultA, int b = DefaultB) { /* ... */ }
};
C object(C::DefaultA, 20);
Or, if you have a lot of parameters with different "defaults:"
struct CParams {
int a, b;
CParams() : a(1), b(2) { }
};
struct C {
C(CParams x) { /* ... */ }
};
CParams params;
params.b = 20;
C object(params);
C++ doesn't support named arguments. You have to specify the first one.
Also, the variable name b from the main function is completely separate from the b in the constructor definition. There's no relationship whatsoever implied by the naming.
I had the same thought (Convienient C++ struct initialisation -- perhaps you find something you like better there) some time ago, but just now, reading your question, I thought of a way to actually accomplish this. But it is quite some extra code, so the question remains if it is actually worth it. I just implemented it very sketchy and I am not proud of my choice of names (I usually don't use _ but it's late). Anyway, this is how you can do it:
#include <iostream>
struct C_members {
int a;
int b;
C_members(int _a, int _b) : a(_a), b(_b) {}
};
class C_init {
public:
virtual C_members get(C_members init) const {
return init;
}
};
class C_a : public C_init {
private:
int a;
public:
C_a(int _a) : a(_a) {}
C_members get(C_members init) const {
init.a = a;
return init;
}
};
class C_b : public C_init {
private:
int b;
public:
C_b(int _b) : b(_b) {}
C_members get(C_members init) const {
init.b = b;
return init;
}
};
class C : private C_members {
private:
static const C_members def;
public:
C(C_init const& ai = C_init(), C_init const& bi = C_init()) : C_members(ai.get(bi.get(def)).a, bi.get(ai.get(def)).b) {
std::cout << a << "," << b << std::endl;
}
};
const C_members C::def(1,2); // default values
// usage:
int main() {
C c1(C_b(77)); // 1,77
C c2(C_a(12)); // 12,2
C c3(C_b(5),C_a(6)); // 6,5
return 0;
}
There is a lot of stuff that can be improved (with templates (for code reduction) and with const refs in the get method), but you get the idea.
As a bonus feature, you almost have the pimpl idiom implemented (very little effort is necessary to extend this to an actual pimpl design).
Usually in OOP, every object instance holds (and represents) a state.
So the best way is to define an accessor functions such as
void setB(int newBvalue);
and also to hold b as a private member.
if "b" is shared among all the instances of the same object, consider to save a static variable.
I have a code that looks something like:
struct Data { int value; };
class A {
public:
typedef std::deque<boost::shared_ptr<Data> > TList;
std::back_insert_iterator<TList> GetInserter()
{
return std::back_inserter(m_List);
}
private:
TList m_List;
};
class AA {
boost::scoped_ptr<A> m_a;
public:
AA() : m_a(new A()) {}
std::back_insert_iterator<A::TList> GetDataInserter()
{
return m_a->GetInserter();
}
};
class B {
template<class OutIt>
CopyInterestingDataTo(OutIt outIt)
{
// loop and check conditions for interesting data
// for every `it` in a Container<Data*>
// create a copy and store it
for( ... it = ..; .. ; ..) if (...) {
*outIt = OutIt::container_type::value_type(new Data(**it));
outIt++; // dummy
}
}
void func()
{
AA aa;
CopyInterestingDataTo(aa.GetDataInserter());
// aa.m_a->m_List is empty!
}
};
The problem is that A::m_List is always empty even after CopyInterestingDataTo() is called. However, if I debug and step into CopyInterestingDataTo(), the iterator does store the supposedly inserted data!
update:
I found the culprit. I actually have something like:
class AA {
boost::scoped_ptr<A> m_a;
std::back_insert_iterator<A::TList> GetDataInserter()
{
//return m_a->GetInserter(); // wrong
return m_A->GetInserter(); // this is the one I actually want
}
// ..... somewhere at the end of the file
boost::scoped_ptr<A> m_A;
};
Now, which answer should I mark as answer?
Really sorry for those not chosen, but you guys definitely got some up-votes : )
The short answer is yes, back_insert_iterator is safe to pass by value. The long answer: From standard 24.4.2/3:
Insert iterators satisfy the
requirements of output iterators.
And 24.1.2/1
A class or a built-in type X satisfies
the requirements of an output iterator
if X is an Assignable type (23.1) ...
And finally from Table 64 in 23.1:
expression t = u
return-type T&
post-condition t is equivalent to u
EDIT: At a glance your code looks OK to me, are you 100% certain that elements are actually being inserted? If you are I would single step through the code and check the address of the aa.m_a->m_List object and compare it to the one stored in outIt in CopyInterestingDataTo, if they're not the same something's fishy.
The following code, which compiles, prints "1", indicating one item added to the list:
#include <iostream>
#include <deque>
#include "boost/shared_ptr.hpp"
#include "boost/scoped_ptr.hpp"
struct Data {
int value;
Data( int n ) : value(n) {}
};
struct A {
typedef std::deque<boost::shared_ptr<Data> > TList;
std::back_insert_iterator<TList> GetInserter()
{
return std::back_inserter(m_List);
}
TList m_List;
};
struct AA {
boost::scoped_ptr<A> m_a;
AA() : m_a(new A()) {}
std::back_insert_iterator<A::TList> GetDataInserter()
{
return m_a->GetInserter();
}
};
struct B {
template<class OutIt>
void CopyInterestingDataTo(OutIt outIt)
{
*outIt = typename OutIt::container_type::value_type(new Data(0));
outIt++; // dummy
}
int func()
{
AA aa;
CopyInterestingDataTo(aa.GetDataInserter());
return aa.m_a->m_List.size();
}
};
int main() {
B b;
int n = b.func();
std::cout << n << std::endl;
}