Can I get a C++ Compiler to instantiate objects at compile time? - c++

I am writing some code that has a very large number of reasonably simple objects and I would like them the be created at compile time. I would think that a compiler would be able to do this, but I have not been able to figure out how.
In C I could do the the following:
#include <stdio.h>
typedef struct data_s {
int a;
int b;
char *c;
} info;
info list[] = {
1, 2, "a",
3, 4, "b",
};
main()
{
int i;
for (i = 0; i < sizeof(list)/sizeof(*list); i++) {
printf("%d %s\n", i, list[i].c);
}
}
Using #C++* each object has it constructor called rather than just being layed out in memory.
#include <iostream>
using std::cout;
using std::endl;
class Info {
const int a;
const int b;
const char *c;
public:
Info(const int, const int, const char *);
const int get_a() { return a; };
const int get_b() { return b; };
const char *get_c() const { return c; };
};
Info::Info(const int a, const int b, const char *c) : a(a), b(b), c(c) {};
Info list[] = {
Info(1, 2, "a"),
Info(3, 4, "b"),
};
main()
{
for (int i = 0; i < sizeof(list)/sizeof(*list); i++) {
cout << i << " " << list[i].get_c() << endl;
}
}
I just don't see what information is not available for the compiler to completely instantiate these objects at compile time, so I assume I am missing something.

In C++ 2011 you can create objects at compile time. For this to happen, you need to make various things constant expressions, however:
The constructor needs to be declared constexpr.
The entity you declare needs to be declared constexpr.
Note, that nearly all your const qualifiers are either irrelevant or in the wrong location. Here is an example with the various correction and also actually demonstrating that the list array is initialized during compile time (by using members of it to define the values of an enum):
#include <iostream>
#include <iterator>
class Info {
int a;
int b;
char const*c;
public:
constexpr Info(int, int, char const*);
constexpr int get_a() const { return a; }
constexpr int get_b() const { return b; }
constexpr char const*get_c() const { return c; }
};
constexpr Info::Info(int a, int b, char const*c)
: a(a), b(b), c(c) {}
constexpr Info list[] = {
Info(1, 2, "a"),
Info(3, 4, "b"),
};
enum {
b0 = list[0].get_b(),
b1 = list[1].get_b()
};
int main()
{
std::cout << "b0=" << b0 << " b1=" << b1 << "\n";
for (Info const* it(list), *end(list); it != end; ++it) {
std::cout << (it - list) << " " << it->get_c() << "\n";
}
}

Related

Creating a pointer to a class in a function belonging to a different class

I'm trying to populate a vector of type pointer to class B, which I'll be using later.
When I try to read the vector's element, the value I'm getting is different from what I've given.
Can someone please help me here, what mistake I'm making and how to correct it?
Thanks
#include <iostream>
#include <vector>
class B {
public:
int b;
B (int n) {
b = n;
}
};
std::vector<B*> v;
class A {
public:
int a;
void func(int n);
};
void A::func(int n) {
B obj_b(n);
B* ptr = &obj_b;
v.push_back(ptr);
}
int main() {
A obj_a;
obj_a.a = 5;
obj_a.func(4);
std::cout<<obj_a.a<<std::endl;
for (auto it:v) {
std::cout<<it->b<<std::endl;
}
}
The output I'm getting is:
5,
32765
Whereas the expected output is:
5,
4
Using value instead of pointer, as per the comments above:
#include <iostream>
#include <vector>
class B {
public:
int b;
B (int n) {
b = n;
}
};
std::vector<B> v;
class A {
public:
int a;
void func(int n);
};
void A::func(int n) {
v.emplace_back(n);
}
int main() {
A obj_a;
obj_a.a = 5;
obj_a.func(4);
std::cout<<obj_a.a<<std::endl;
for (auto& e:v) {
std::cout<<e.b<<std::endl;
}
}
You can use heap allocations and take advantage of std::unique_ptr<T>. Here is the fix:
#include <iostream>
#include <vector>
#include <memory>
class B
{
public:
B ( const int n )
{
b = n;
}
int b;
};
std::vector< std::unique_ptr<B> > v; // use a vector of B pointers
// ( std::unique_ptr<B> )
class A
{
public:
void func( const int n );
int a;
};
void A::func( const int n )
{
v.push_back( std::make_unique<B>( n ) ); // returns a pointer object of type
} // std::unique_ptr<B>
int main ()
{
A obj_a;
obj_a.a = 5;
obj_a.func( 4 );
std::cout << obj_a.a << std::endl;
for ( const auto& ptrB : v )
{
std::cout << ptrB->b << std::endl; // use -> operator to have access to
} // ptrB's members
return 0;
}
Hopefully, this helps.

Is there std::variant and std::visit way to replace old legacy dispatch for messy code?

There is an old legacy code which can not be modified. If simplified it looks like this:
enum class Type {A, B, C};
struct Object {Type type;};
Object* objs[N];
int count = 0;
#define addobj(ptr) objs[count++] = (Object*)ptr
struct A {
Type type;
int prop1;
A(int v) : type(Type::A), prop1(v) {addobj(this);}
};
struct B {
Type type;
int prop1;
B(int v) : type(Type::B), prop1(v) {addobj(this);}
};
struct C {
Type type;
int prop1;
C(int v) : type(Type::C), prop1(v) {addobj(this);}
};
A* getA(int id) {return (A*)objs[id];}
B* getB(int id) {return (B*)objs[id];}
C* getC(int id) {return (C*)objs[id];}
In addition, there is "polymorphic" property access, which is allowed to change:
int& prop1ref(int id) {
switch (objs[id]->type) {
case Type::A: return getA(id)->prop1;
case Type::B: return getB(id)->prop1;
}
return getC(id)->prop1;
}
void test() {
A a(1); B b(2); C c(3);
for (int id=0; id<count; id++)
prop1ref(id);
}
Is there a way to replace only property access code in prop1ref with e.g. std::variant and std::visit?
Please note, prop1 name and type do match between classes, but locations (offsets) do not. Type field offset is guaranteed so cast can always be made. Also, new code should allow accessing double prop2, string prop3 etc in A, B, C classes without using macros.
Possibly something like this:
#include <variant>
#include <type_traits>
#include <iostream>
// ...
std::variant<A*, B*, C*> fetch_from_id(int const id) {
switch (objs[id]->type) {
case Type::A: return getA(id);
case Type::B: return getB(id);
default: return getC(id);
}
}
void test() {
A a(1); B b(2); C c(3);
for (int id = 0; id < count; id++)
std::visit([] (auto&& v) {
using type = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<type, A*>) {
// For A
std::cout << v->prop1 << std::endl;
}
if constexpr (std::is_same_v<type, B*>) {
// For B
std::cout << v->prop1 << std::endl;
}
if constexpr (std::is_same_v<type, C*>) {
// For C
std::cout << v->prop1 << std::endl;
}
}, fetch_from_id(id));
}
If you want to see for yourself if it works:
Demo
The below will allow you to extract other properties in a very easy way using lambdas:
#include <variant>
#include <string>
#include <iostream>
enum class Type {A, B, C};
struct Object {Type type;};
Object* objs[3];
int count = 0;
#define addobj(ptr) objs[count++] = (Object*)ptr
struct A {
Type type;
int prop1;
A(int v) : type(Type::A), prop1(v) {addobj(this);}
};
struct B {
Type type;
int prop1;
B(int v) : type(Type::B), prop1(v) {addobj(this);}
};
struct C {
Type type;
int prop1;
C(int v) : type(Type::C), prop1(v) {addobj(this);}
};
A* getA(int id) {return (A*)objs[id];}
B* getB(int id) {return (B*)objs[id];}
C* getC(int id) {return (C*)objs[id];}
using var_t = std::variant<A*,B*,C*>;
var_t fetch_from_id(int const id) {
switch (objs[id]->type) {
case Type::A: return getA(id);
case Type::B: return getB(id);
default: return getC(id);
}
}
// straightforward lambdas for extracting any property from your objects
auto get_prop1 = [](auto&& t){ return t->prop1;};
auto get_prop2 = [](auto&& t){ return t->prop2;};
auto get_prop3 = [](auto&& t){ return t->prop3;};
int main()
{
A a(1); B b(2); C c(3);
// print prop1
for (int id=0; id<3; id++) std::cout << std::visit(get_prop1, fetch_from_id(id)) << " ";
std::cout << std::endl;
// print prop2
// for (int id=0; id<3; id++) std::cout << std::visit(get_prop2, fetch_from_id(id)) << " ";
// std::cout << std::endl;
// print prop3
// for (int id=0; id<3; id++) std::cout << std::visit(get_prop3, fetch_from_id(id)) << " ";
// std::cout << std::endl;
}
Live code here

Is it possible to pass a struct's member variable as parameter

I am trying to associate a struct's member variable with a class. So that when I create a new class, I can specify that it is associated with this member variable in a struct. For example:
struct A {
int a;
int b;
};
static A a[2];
a[0].a = 1;
a[0].b = 2;
a[1].a = 3;
a[1].b = 4;
class foo {
public:
foo(int index, ???) {
c = a[index].???; //Is it possible to define the 2nd parameter as a getter of struct A's member? So this line could resolve to either a[index].a or a[index].b?
}
private:
int c;
};
So that:
new foo(0, ???) would set c to 1 given ??? refer to A::a
new foo(0, ???) would set c to 2 given ??? refer to A::b
new foo(1, ???) would set c to 3 given ??? refer to A::a
new foo(1, ???) would set c to 4 given ??? refer to A::b
Yes, it is possible, you need to pass a data member pointer:
#include <iostream>
struct A
{
int a;
int b;
};
static A a[2]
{
1, 2
, 3, 4
};
class foo
{
public: int c;
public:
foo(int const index, int A::* const p_field)
{
c = a[index].*p_field;
}
};
int main()
{
foo const f1(0, &A::a);
::std::cout << f1.c << ::std::endl;
foo const f2(0, &A::b);
::std::cout << f2.c << ::std::endl;
foo const f3(1, &A::a);
::std::cout << f3.c << ::std::endl;
foo const f4(1, &A::b);
::std::cout << f4.c << ::std::endl;
return 0;
}
Check this code at online compiler
You have a couple options. If you just want the integer (like you have in your code you've posted), then just take an integer as a parameter to the constructor and pass it the right number.
class foo {
public:
foo(int val) {
c = val
}
private:
int c;
};
int main() {
foo f(a[0].b);
}
Or you could take a reference to an integer. This way if one changes, the other will as well:
class foo {
public:
foo(int &val) : c(val) { } //need to use an initialization list for this one
private:
int &c;
};
int main() {
foo f(a[0].b);
a[0].b = -1; //f.c will be -1 now as well
}
Using a data member pointer as in VTT's answer is the most direct solution but I often find member pointers and member function pointer syntax a bit cumbersome and I believe it is hard for the compiler to optimize.
For these kind of things I prefer to use a stateless lambda. You can pass a lambda to a function template and then the compiler can easily optimize it away:
#include <iostream>
struct A {
int a;
int b;
};
static A a[2]{{1, 2}, {3, 4}};
class foo {
public:
int c;
public:
template<typename F>
foo(int index, F getter) { c = getter(a[index]); }
};
int main() {
auto agetter = [](const A& a){ return a.a; };
auto bgetter = [](const A& a){ return a.b; };
foo const f1(0, agetter);
std::cout << f1.c << "\n";
foo const f2(0, bgetter);
std::cout << f2.c << "\n";
foo const f3(1, agetter);
std::cout << f3.c << "\n";
foo const f4(1, bgetter);
std::cout << f4.c << "\n";
}

Accessing a parameter via a C++ function object class

#include <iostream>
struct A {
explicit A(int a) : _a(a) {};
int _a;
};
struct ClassFunction {
ClassFunction(std::shared_ptr<A> myA) : _myA(myA) {}
double operator() (int &x,
int &g) {
return 1.0
+ static_cast<double>(_myA->_a); // offending line
}
static double wrap(int x, int g, void *data) {
return (*reinterpret_cast<ClassFunction*>(data)) (x,g);
}
std::shared_ptr<A> _myA;
};
int main() {
int x = 1;
int g;
auto myA = std::shared_ptr<A>(new A(int(20)));
ClassFunction myClassFunction(myA);
std::cout << ClassFunction::wrap(x,g,NULL) << std::endl;
return 0;
}
I'm trying to create a function object class ClassFunction that takes a std::shared_ptr<A> as a parameter, which I then call via the static member function ClassFunction::wrap.
If I access a data member of A as myA->_a the program fails to run (it does compile without any complaint, however).
How do I make this work?
Try the following:
std::cout << ClassFunction::wrap(x, g, &myClassFunction) << std::endl;
reinterpret_cast< ClassFunction*>(data) is applicable when the data points to instance of ClassFunction class.

Accessing memory past the class

I have a peculiar problem. I want to create classes with variable length arrays in them. I don't want to allocate the arrays on the heap for the reasons of locality (the code slows down by a factor of 2 when I do). I don't want to use a virtual function because I don't want to pay for a function call. The following code works (on my compiler/platform), but with a caveat.
include <iostream>
include <boost/array.hpp>
struct Base
{
Base(size_t s):
size(s) {}
int& up(size_t i) { return *(reinterpret_cast<int*>((&size) + 1) + i); }
size_t size;
};
template<size_t sz>
struct Derived: public Base
{
boost::array<int, sz> data;
Derived(): Base(sz) {}
};
int main()
{
Derived<5> d5;
d5.data[2] = 1234;
Base* b = &d5;
std::cout << b->up(2) << std::endl;
}
This is incredibly ugly; the reinterpret_cast<...> is a red flag. Moreover, the caveat is that this fails if I change size_t to, say, short unsigned (I guess the compiler pads the class).
So the question is: is there a way to make this portable? Is there a way to determine from Base where the first member variable will sit in its derived class?
Just an idea that came to my mind: let the Derived constructor store a pointer to its data inside a Base member.
struct Base
{
protected:
size_t size;
int * array;
Base(size_t s, int * arr):
size(s), array(arr)
{ }
public:
int& up(size_t i) { return array[i]; }
size_t getSize() { return size; }
};
template<size_t sz>
struct Derived: public Base
{
std::array<int, sz> data;
Derived():
Base(sz, &data[0])
{ }
};
int main()
{
Derived<5> d5;
d5.data[2] = 1234;
Base* b = &d5;
std::cout << b->up(2) << std::endl;
}
From your comment, it sounds like something like this might suffice:
#include <cstddef>
#include <array>
#include <algorithm>
template <typename T>
struct ArrayBase
{
typedef T type;
type & operator[](std::size_t i) { return buf[i]; }
type const & operator[](std::size_t i) const { return buf[i]; }
protected:
ArrayBase(type * p) : buf(p) { }
private:
type * buf;
};
template <typename T, std::size_t N>
struct Array : ArrayBase<T>
{
Array()
: ArrayBase<T>(a.data())
{
}
Array(Array const & rhs)
: ArrayBase<T>(a.data())
{
std::copy(rhs.a.begin(), rhs.a.end(), a.begin());
}
private:
std::array<T, N> a;
};
Usage:
Array<int, 5> a5;
ArrayBase<int> & b = a5;
b[2] = 11;
Array<int, 5> a52 = a5;
a52[2] = 13;
Here's a dangerous, but fast and small answer:
template<class T>
struct alloca_magic {
T* b;
int s;
alloca_magic(void* bu, int sz)
: b((T*)(bu)),s(sz)
{new(b)T[s];}
~alloca_magic()
{for(int i=0;i<s;++i)(b+i)->~T();}
operator T*() {return b;}
};
#define alloca_magic(Type,Name,Size) void* t = alloca(sizeof(Type)*Size); alloca_magic<Type> Name(t,Size);
#include <iostream>
struct test {
int data;
test() {std::cout << "ctor\n";}
~test() {std::cout << "dtor\n";}
};
void foo(int len) {
std::cout << "begin foo\n";
alloca_magic(test ,buffer,len);
for(int i=0; i<len; i++)
buffer[i].data = i;
std::cout << "end foo\n";
}
int main() {
int len;
std::cin >> len;
std::cout << "begin main\n";
alloca_magic(test ,buffer,len);
for(int i=0; i<len; i++)
buffer[i].data = i;
foo(len);
std::cout << "end main\n";
}
http://ideone.com/ccvTR results:
begin main
ctor
ctor
ctor
begin foo
ctor
ctor
ctor
end foo
dtor
dtor
dtor
end main
dtor
dtor
dtor
For windows you'll have to replace alloca with _alloca. Keep in mind that this is easily abused and broken, and if done with large numbers can cause a stack overflow. I do not recommend this for anything besides speed tests, and probably not then either.