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

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";
}

Related

Safe way to reference nested member

I have a struct with some other structs as member. Both external and internal structs are StandardLayout (it can be even assumed that internal are plain old data). Something like this:
struct Inner1 {
int a = 0, b = 0;
};
struct Inner2 {
int c = 0, d = 0;
};
struct Outer {
Inner1 x;
std::string s;
Inner2 y;
};
I want to write some function that takes Outer& and object of some type T that can return value of any nested field, depending on argument:
int get(Outer& o, T field);
If Outer was a flat structure, pointers to member would be exactly what I needed, however it is not flat.
The trivial way is to make T a enum of all fields and write a switch, but I it it not efficient. The faster way is to make T an offset and write
int get(Outer& o, size_t field) {
return *reinterpret_cast<int*>(reinterpret_cast<char*>(o) + field);
}
and then call it like get(o, offsetof(Outer, y) + offsetof(Inner2, c)). It works, but I am not sure if it is guaranteed to work - if it is correct to sum offsets like this and if it is safe to take member value by offset.
So, the question: is this way safe? If not, is there a safe way? Constructing values of T can be arbitrary complex, however using them should be fast.
Motivation: I will need to put values from some of nested fields in some order, known at startup, but not in compile time. I wanted to create an array of T at startup and then, when getting particular object, use this precalced array.
[UPD]: So it will be used like this:
void bar(int);
void foo(Outer& o, vector<T>& fields) {
for (auto& field : fields) {
bar(get(o, field));
}
}
You can do it this way.
/* main.cpp */
#include <string>
#include <iostream>
using namespace std;
struct Inner1 {
int a = 0, b = 0;
};
struct Inner2 {
int c = 0, d = 0;
};
struct Outer {
Inner1 x;
std::string s;
Inner2 y;
};
struct OuterMember
{
int (*getter)(Outer &obj);
};
inline int get(Outer &obj,OuterMember field) { return field.getter(obj); }
template <auto Ptr1,auto Ptr2>
auto GetInnerMember(Outer &obj) { return (obj.*Ptr1).*Ptr2; }
inline constexpr OuterMember OuterMemberA = { GetInnerMember<&Outer::x,&Inner1::a> } ;
inline constexpr OuterMember OuterMemberB = { GetInnerMember<&Outer::x,&Inner1::b> } ;
inline constexpr OuterMember OuterMemberC = { GetInnerMember<&Outer::y,&Inner2::c> } ;
inline constexpr OuterMember OuterMemberD = { GetInnerMember<&Outer::y,&Inner2::d> } ;
/* main() */
int main()
{
Outer obj;
obj.x.a=1;
obj.x.b=2;
obj.y.c=3;
obj.y.d=4;
cout << "a = " << get(obj,OuterMemberA) << endl ;
cout << "b = " << get(obj,OuterMemberB) << endl ;
cout << "c = " << get(obj,OuterMemberC) << endl ;
cout << "d = " << get(obj,OuterMemberD) << endl ;
return 0;
}
I do think this is safe (as in not a violation of strict aliasing).
However, the language does have a better mecanism for doing this: Pointers to data members, which compile down to basically an offset.
The caveat is that you'll have to make separate overloads for Inner1 and Inner2
int get(Outer& o, int Inner1::* m) {
return o.x.*m;
}
int get(Outer& o, int Inner2::* m) {
return o.y.*m;
}
int foo() {
Outer tmp;
return get(tmp, &Inner1::a) + get(tmp, &Inner2::d);
}
You can achieve the same using function template specialization see sample code below
#include <iostream>
using namespace std;
struct Inner1 {
int a = 1, b = 2;
};
struct Inner2 {
int c = 3, d = 4;
};
struct Outer {
Inner1 x;
std::string s;
Inner2 y;
};
template<typename T>
int get(Outer&o);
template<>
int get<Inner1>(Outer& o)
{
return o.x.a;
}
template<>
int get<Inner2>(Outer& o)
{
return o.y.c;
}
int main()
{
Outer out;
std::cout << get<Inner1>(out) << std::endl;
std::cout << get<Inner2>(out) << std::endl;
return 0;
}
I hope this helps!. The more interesting thing is that this is type safe.

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.

How to get n-th attribute of class in C++

With a normal class. For example:
class A {
public:
int a;
std::string b;
A() {}
~A() {}
}
We can do:
A x;
x.a = 1;
x.b = "hello";
But now I don't want to do like above. I want to access n_index-th attribute of object. For example pseudo like x.get<2>() (or x.set<2>(...)) like x.b.
How can do that? Have any template for that.
Beside if I want code like that
int number = 2;
x.get<number>()
Any problem with constexpr?
I think the closest you can get is using boost::fusion.
An example would be
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/mpl/int.hpp>
#include <iostream>
class A {
public:
int a;
std::string b;
A() {}
~A() {}
};
BOOST_FUSION_ADAPT_STRUCT(A,
(int, a)
(std::string, b)
)
using namespace boost::fusion;
int main()
{
A x;
x.a = 1;
x.b = "hello";
std::cout << at<boost::mpl::int_<0>>(x) << '\n';
std::cout << at<boost::mpl::int_<1>>(x) << '\n';
at<boost::mpl::int_<0>>(x) = 5;
at<boost::mpl::int_<1>>(x) = std::string("World");
std::cout << at<boost::mpl::int_<0>>(x) << '\n';
std::cout << at<boost::mpl::int_<1>>(x) << '\n';
}
If you want to set several values at the same time when you create the object, you could use a multi-parameter constructor. For example, let's imagine you have this:
class A {
public:
int a;
std::string b;
A() {}
~A() {}
};
You could add a constructor that sets a and b:
class A {
public:
int a;
std::string b;
A() {}
A(int a, std::string b) {
this->a = a;
this->b = b;
}
~A() {}
};
That way, you can create your object and set a and b with :
A a = A(1, "hello");
There is no ready-made way of setting the n-th attribute of your object. You could make one, but I would very, very highly recommend that you don't. Like I said above, if you reorder your attributes, then you will have to rework everything.
If you really, really want to make your life very, very, very much harder, a very ugly and error-prone way of doing this would be like :
template<class T>
void A::setNth(int nth, const T& value) {
switch (nth) {
case 1: a = value; break;
case 2: b = value; break;
// You should #include <stdexcept> to use runtime_error, or you could handle the exception in some other way.
default: throw std::runtime_error("A::setNthAttribute : Value of nth is out of bounds.");
}
}
For the getter:
template<class T>
void A::getNth(int nth, T& valueOut) {
switch (nth) {
case 1: valueOut = a; break;
case 2: valueOut = b; break;
default: throw std::runtime_error("A::getNthAttribute : Value of nth is out of bounds.");
}
}
You would use these methods like this:
A a;
a.setNth(1, 2); // put 2 into a
int i;
a.getNth(1, i); // put a into i
Just writing this code send shivers down my spine. Please, never write what I just wrote. Chuck Norris will kill yoU agfh
86sd asdsa dDASD8!4.
What you are considering is in fact possible, but a bit of a headache. I would approach it by creating a template getter and setter for every member that one can set or get, and then having a template method that takes an int and sets or gets the appropriate property. The getters/setters would have to be specialized for the correct type, and throw an error for other types. This method would have to use a switch to return the right member:
class bar {
private:
int a;
std::string b;
template<T>
T getA() {
// error
}
template<T>
T getB() {
// error
}
template<T>
void setA(const T& A) {
// error
}
template<T>
void setB(const T& B) {
// error
}
template <> std::string getB(); // specialization
template <> int getA();
template <> void setB(const std::string&);
template <> void setA(int);
public:
template<T>
T get(int what) {
switch(what) {
case 1:
return getA();
case 2:
return getB();
default:
// handle error here
break;
}
}
template<T>
void set(int what, const T& t) {
switch(what) {
case 1:
return setA<T>(t);
case 2:
return setB<T>(t);
default:
// handle error here
break;
}
}
};
bar b;
b.set<std::string>(2, "foo");
auto str = b.get<std::string>(2);
Here's an elaborate way to accomplish what you want.
#include <iostream>
#include <string>
// A namespace explicitly defined for class A.
namespace A_NS
{
// A template for members of A.
template <int> struct Member;
// Specialization for the first member.
template <> struct Member<1>
{
using type = int;
type var;
};
// Specialization for the second member.
template <> struct Member<2>
{
using type = std::string;
type var;
};
}
class A {
public:
A() {}
~A() {}
template <int N> typename A_NS::Member<N>::type get() const
{
return static_cast<A_NS::Member<N> const&>(members).var;
}
template <int N> void set(typename A_NS::Member<N>::type const& in)
{
static_cast<A_NS::Member<N>&>(members).var = in;
}
private:
// Define a type for the member variables.
struct Members : A_NS::Member<1>, A_NS::Member<2> {};
// The member variables.
Members members;
};
int main()
{
A a;
a.set<1>(10);
a.set<2>("test");
std::cout << a.get<1>() << ", " << a.get<2>() << std::endl;
}
Output:
10, test

C++ static const members overriding

Consider the following.
struct A {
static const int X = 1;
static void printX() {std::cout << "X " << X << std::endl; };
};
struct B: public A {
static const int X = 2;
};
int main(argc argv){
B b;
b.printX();
}
How to force the b.printX() to print value 2?
Both - constant and method - MUST be static. And therefore, virtual methods are not suitable.
For anyone who thinks they know my task better than me and wants to see me rethinking it, I'll explain the goal of my efforts :)
Just imagine class which has behaviour based on set of static constants. The simplest way to implement child class with different set of constants and therefore with different behaviour is derivation of class from previous one with specific set of constant values. It is possible to solve that task using virtual functions. Of cause possible, no question. But this solution will be not very pure in sense of accordance to a theory of modeled entities. Usage of virtual methods in this case will be more a trick than correct implementation.
For example, IR channels have different timing of pulse durations and package structure. It is convenient to define set of child classes (different IR channel implementations) with a specific set of constant values. That values are static because they are common for every object of class and const because they are needed at compile time only. And because internal implementations of base and child classes are slightly different the best relationship between of them are super class - child class.
Is it rationale for my original question now?
You are going to need a template, and to change the inheritance to use the template, as you will see. The trick is to make it work whether the derived class has an X to overshadow the base-class X or not.
template<class C>
struct A {
static const int X = 1;
template<typename T>
static int getX(decltype(T::X)*)
{ return T::X; }
template<typename T>
static void getX(...)
{ return X; }
static void printX()
{ std::cout << "X " << getX<C>(0) << std::endl; }
};
struct B: public A<B> {
static const int X = 2;
};
struct B2: public A<B2> {
// No X
};
int main(){
B b;
b.printX(); // Prints X 2
B2 b2;
b2.printX(); // Prints X 1
}
Just make the value of X a template parameter:
#include <iostream>
template<int XValue=1>
struct A {
static const int X = XValue;
static void printX() {std::cout << "X " << X << std::endl; };
};
template<int XValue=2>
struct B: public A<XValue> {
};
struct C: public B<3> {
};
int main(int, char**){
B<> b;
b.printX();
}
By definition, anything you do with static members will be "overshadowing", not "overriding". You could reimplement "printX()" in "B", but you would not really be overriding the behavior; because this would use overshadowing, the behavior would depend entirely on the compile-time, not runtime, type.
Instead of using static and template, I would just use regular constant attributes and constructors.
For example:
#include <iostream>
struct A {
A(const char* fn, const int X) : filename(fn), X(X) {};
void print() { std::cout << "X = " << X << ", FN = " << filename << std::endl; };
protected:
const char* filename;
const int X;
};
struct B : public A {
B() : A("data.dat", 5) {};
};
int main(int, char **) {
B b;
b.print();
}
Functionally, it does exactly what you want. Output:
X = 5, FN = data.dat
— It's now the compiler's job to optimize those constants. And if you are not intending to use thousands of objects B, it's probably not worth worrying about making those constants static.
Short answer: you can't.
Slightly longer, more complex answer: Well, maybe you can. With templates!
#include <iostream>
template <typename T> struct A
{
static const int X = 1;
static void printX()
{
std::cout << "X=" << T::X << std::endl;
}
};
struct B : public A<B>
{
static const int X = 2;
};
int main(int, char **)
{
B b;
b.printX();
return 0;
}
OK, I'll play along... you want to nest this more than one level deep. Fine.
#include <iostream>
template <int XX> struct T
{
static const int X = XX;
static void printX()
{
std::cout << "X=" << X << std::endl;
}
};
struct AA
{
static const int X = 1;
/* all other members go here */
};
struct A : public AA, public T<AA::X>
{
/* empty - put stuff in AA instead */
};
struct BB : public AA
{
static const int X = 2;
};
struct B : public BB, public T<BB::X>
{
};
struct CC : public BB
{
static const int X = 3;
};
struct C : public CC, public T<CC::X>
{
};
struct DD : public CC
{
static const int X = 4;
};
struct D : public DD, public T<DD::X>
{
};
int main(int, char **)
{
A a;
B b;
C c;
D d;
a.printX();
b.printX();
c.printX();
d.printX();
return 0;
}
You could even skip the static const int X = ...; in every class, and just do public T<1>, public T<2> etc as necessary.

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

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";
}
}