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);
}
Related
Let's say I have a code like this
#include <iostream>
#include <vector>
#include <memory>
#using namespace std;
class animal{
protected:
int height;
int speed;
};
class horse:public animal{
public:
horse(){
height=200;
speed=75;
}
};
class cat:public animal{
public:
cat(){
height=30;
speed=20;
}
};
class dog:public animal{
public:
dog(){
height=55;
speed=35;
}
};
int main() {
std::vector<std::unique_ptr<animal>>animalvector;
animalvector.emplace_back((unique_ptr<animal>(new horse)));
animalvector.emplace_back((unique_ptr<animal>(new cat)));
animalvector.emplace_back((unique_ptr<animal>(new dog)));
return 0;
}
I want to sort this animalvector in a descending order based on the speed of these different animals. What's the best method to do it?
You can use std::sort from <algorithm> with a lambda function define your sorting predicate.
std::sort(animalvector.begin(),
animalvector.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs->speed > rhs->speed;
});
Note that speed would either need to be public or you'd need a public getter function. If you wanted to add getter methods
class animal
{
public:
int GetHeight() const { return height; }
int GetSpeed() const { return speed; }
protected:
int height;
int speed;
};
then you'd modify the lambda to use these getters
std::sort(animalvector.begin(),
animalvector.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs->GetSpeed() > rhs->GetSpeed();
});
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();
}
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, " "));
}
class cat
{public:
void dog(int ID, char *value) // int ID I'd like to be the index array it was called from?
{
debug(ID, value);
}
}
cat cats[18];
cats[1].dog("value second arg, first arg auto filled from index array");
I want something similar to this.
include <vector>
class CatArray;
class Cat {
// This line means that the CatArray class can
// access the private members of this class.
friend class CatArray;
private:
static int ID;
public:
void dog(const char* value) {
// Use ID here any way you want.
}
};
int Cat::ID = 0;
class CatArray {
private:
std::vector<Cat> cats;
public:
explicit CatArray(unsigned int size) : cats(size) {}
Cat& operator [](unsigned int index) {
Cat::ID = index;
return cats[index];
}
};
But a little different. There are 18 Clients in a game and i need to basically do this. for eg, "Client 4 Chooses an option and the option gets called through the array index and than that way client 4 will call the function with the function holding the index 4"
Then cats[1] is not really a Cat object but a CatWithIndex object:
class Cat {
public:
void dog(size_t index,const char* value);
};
class CatWithIndex {
size_t index_;
const Cat &cat_;
public:
CatWithIndex(size_t index, const Cat &cat): index_(index), cat_(cat) {}
void dog(const char* value) {
cat_.dog(index_,value);
}
};
class CatArray {
private:
std::vector<Cat> cats;
public:
Cat& operator [](unsigned int index) {
Cat::ID = index;
return CatWithIndex(index,cats[index]);
}
};
I'm trying to store a set of std::function in a map (under GCC 4.5)
I'd like to get 2 kind of things :
storing functions with arguments already passed; then you just have
to call f()
storing functions without arguments; then you have to call
f(...)
I think I achieved the first one with a class Command and a Manager :
class Command
{
std::function<void()> f_;
public:
Command() {}
Command(std::function<void()> f) : f_(f) {}
void execute() { if(f_) f_(); }
};
class CommandManager
{
typedef map<string, Command*> FMap;
public :
void add(string name, Command* cmd)
{
fmap1.insert(pair<string, Command*>(name, cmd));
}
void execute(string name)
{
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
Command* c = it->second;
c->execute();
}
}
private :
FMap fmap1;
};
can be used like this :
class Print{
public:
void print1(string s, string s1){ cout<<"print1 : "<<"s : "<<s<<" s1 : "<<s1<<endl; }
int print2(){ cout<<"print2"<<endl; return 2;}
};
#include <string>
#include <functional>
int main()
{
Print p = Print();
function<void()> f1(bind(&Print::print1, &p, string("test1"), string("test2")));
function<int()> f2(bind(&Print::print2, &p));
CommandManager cmdMgr = CommandManager();
cmdMgr.add("print1", new Command(f1));
cmdMgr.execute("print1");
cmdMgr.add("print2", new Command(f2));
cmdMgr.execute("print2");
return 0;
}
Now I'd like to be able to do this :
int main()
{
Print p = Print();
function<void(string, string)> f1(bind(&Print::print1, &p, placeholders::_1, placeholders::_2));
CommandManager cmdMgr = CommandManager();
cmdMgr.add("print1", new Command(f1));
cmdMgr.execute("print1", string("test1"), string("test2"));
return 0;
}
Is there a way, using type-erasure for example ?
You could use dynamic cast to determine the type of the function in the list at runtime.
Please note that I added shared_ptr to remove the memory leak in the original sample. Perhaps you want to throw a exception if the execute method is called with the wrong arguments (if the dynamic_cast yields 0).
Usage:
void x() {}
void y(int ) {}
void main() {
CommandManager m;
m.add("print", Command<>(x));
m.add("print1", Command<int>(y));
m.execute("print");
m.execute("print1", 1);
}
Code (with variadic template support for example gcc-4.5):
#include <functional>
#include <map>
#include <string>
#include <memory>
using namespace std;
class BaseCommand
{
public:
virtual ~BaseCommand() {}
};
template <class... ArgTypes>
class Command : public BaseCommand
{
typedef std::function<void(ArgTypes...)> FuncType;
FuncType f_;
public:
Command() {}
Command(FuncType f) : f_(f) {}
void operator()(ArgTypes... args) { if(f_) f_(args...); }
};
class CommandManager
{
typedef shared_ptr<BaseCommand> BaseCommandPtr;
typedef map<string, BaseCommandPtr> FMap;
public :
template <class T>
void add(string name, const T& cmd)
{
fmap1.insert(pair<string, BaseCommandPtr>(name, BaseCommandPtr(new T(cmd))));
}
template <class... ArgTypes>
void execute(string name, ArgTypes... args)
{
typedef Command<ArgTypes...> CommandType;
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
CommandType* c = dynamic_cast<CommandType*>(it->second.get());
if(c)
{
(*c)(args...);
}
}
}
private :
FMap fmap1;
};
without variadic template support (example VS2010):
#include <functional>
#include <map>
#include <string>
#include <memory>
using namespace std;
class Ignored;
class BaseCommand
{
public:
virtual ~BaseCommand() = 0 {};
};
template <class A1 = Ignored>
class Command : public BaseCommand
{
typedef std::function<void(A1)> FuncType;
FuncType f_;
public:
Command() {}
Command(FuncType f) : f_(f) {}
void operator()(const A1& a1) { if(f_) f_(a1); }
};
template <>
class Command<Ignored> : public BaseCommand
{
typedef std::function<void()> FuncType;
FuncType f_;
public:
Command() {}
Command(FuncType f) : f_(f) {}
void operator()() { if(f_) f_(); }
};
class CommandManager
{
typedef shared_ptr<BaseCommand> BaseCommandPtr;
typedef map<string, BaseCommandPtr> FMap;
public :
template <class T>
void add(string name, const T& cmd)
{
fmap1.insert(pair<string, BaseCommandPtr>(name, BaseCommandPtr(new T(cmd))));
}
template <class A1>
void execute(string name, const A1& a1)
{
typedef Command<A1> CommandType;
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
CommandType* c = dynamic_cast<CommandType*>(it->second.get());
if(c)
{
(*c)(a1);
}
}
}
void execute(string name)
{
typedef Command<> CommandType;
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
CommandType* c = dynamic_cast<CommandType*>(it->second.get());
if(c)
{
(*c)();
}
}
}
private :
FMap fmap1;
};
What you are trying to do is not possible without some serious runtime work and the associated cost. The simplest solution would of course to just store a boost::any (any_function never made it into boost) inside your map and do the necessary casts (or add some runtime data that tells you which cast to make), although you should avoid that at any cost and go with fixed arguments or no arguments.
Your users can then modify their functions using bind to match the signature you require.
Edit: In your current scheme I see no reason for CommandManager to store Command* in the map.
Edit2: Also you drop the return type. This could be OK for your use-case but makes this a lot less generic.
Edit3: I worked out some working example of your code using any. I feel that there is some flaw and I really don't see what this should achieve but here it goes:
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <boost/any.hpp>
class AnyCaller
{
std::map<std::string, boost::any> calls;
public:
AnyCaller() {}
void add(const std::string& name, const boost::any& fun) {
calls[name] = fun;
}
// we always use the throwing version of any_cast
// icbb by error checking
// no arg version
template<typename Ret>
Ret call(const std::string& s) {
const boost::any& a = calls[s];
return boost::any_cast< std::function<Ret(void)> >(a)();
}
// this should be a variadic template to be actually usable
template<typename Ret, typename T>
Ret call(const std::string& s, T&& arg) {
// we have to assume that our users know what we are actually returning here
const boost::any& a = calls[s];
return boost::any_cast< std::function<Ret(T)> >(a)(std::forward<T>(arg));
}
virtual ~AnyCaller() {}
};
int foo() { std::cout << "foo" << std::endl; return 1; }
double foo2(int i) { std::cout << "foo2" << std::endl; return double(i); }
int main()
{
AnyCaller c;
c.add("foo", std::function<int(void)>(foo));
c.add("foo2", std::function<double(int)>(foo2));
c.call<int>("foo");
c.call<double, int>("foo2", 1);
// this should throw
c.call<double, int>("foo", 1);
return 0;
}
As for the example using a fixed signature. Just think of what would be the most natural representation of a function you are going to store (looking at your Command example I'd assume it is std::function<void(void)>. Store functions of this type and whenever one your users tries to use it, he has to bind whatever function he wants to use, so it matches this signature.
Your Command class constructor needs a function<void()>. You are trying to feed it a function<void(string,string)>. This is not going to typecheck.
If you need functions that accept variable arguments (like printf), you will need function<> and execute() that accept variable arguments. You need to know how to work with that (in particular, you need a fixed first argument). You are then responsible for type safety, much like with printf.
If you just need a variable number of string arguments, use functions that accept e.g. vectors of strings.
All this has nothing to do whatsoever with std::map. Whatever you can store in a plain old variable, you can store in std::map too.