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.
Related
in the following code example I am about to call concrete foo() function with already initialized arguments vect via run() method. For compilation I use VS19 with C++17. In the following I am not sure about my usage of std::apply... Any kind of help is welcomed ;)
#include <iostream>
#include <vector>
#include <tuple>
using namespace std;
template<typename ...T>
struct Base {
vector<int> vect;
Base(){
static const std::size_t size = sizeof...(T);
for (int i = 0; i < size; i++)
vect.push_back((i+1)*(i+1)); //some initialization
}
};
template<typename ...T>
struct Derived : public Base<T...> {
virtual int foo(T...) = 0;
int lastResult;
void run() {
if (this->vect.size() > 0) {
lastResult = std::apply(foo, this->vect);
}else{
lastResult = -1;
cout << "0 arguments case" << endl;
}
}
};
struct D0 : public Derived<> {
int foo() override { return 0; }
};
struct D1 : public Derived<int> {
int foo(int a) override { return a * a; }
};
struct D2 : public Derived<int,int> {
int foo(int a, int b) override { return a + b; }
};
int main() {
D0 d0;
cout << d0.foo() << endl; // 0
//d0.run(); //vect = {}, lastResult = -1, "0 arguments case"
D1 d1;
cout << d1.foo(1) << endl; // 1
//d1.run(); //vect = {1} -> lastResult = 1
D2 d2;
cout << d2.foo(1, 2) << endl; // 3
//d2.run(); //vect = {1,4} -> lastResult = 5
cin.get();
}
Using std::index_sequence from C++14 helps with this kind of stuff:
Make a second version of run that takes a sequence of size_t template arguments, and use std::index_sequence_for to fill them:
template <size_t... Is>
void runImpl(std::index_sequence<Is...>) { ... }
void run() { return runImpl(std::index_sequence_for<T...>{}); }
Then, in runImpl, you can expand the template integers to pass vector values as function parameters:
if (this->vect.size() > 0) {
lastResult = foo(Base<T...>::vect[Is]...);
}else{
lastResult = -1;
cout << "0 arguments case" << endl;
}
Demo: https://godbolt.org/z/ZGroAH
In the following I am not sure about my usage of std::apply...
I see two problems in your usage of std::apply()
(1) std::apply() require a std::tuple, or similar, for second argument. For "or similar" I mean "or std::array or std::pair".
So your std::vector doesn't works.
I suppose you can use a std::array.
I propose the following Base
template<typename ...T>
struct Base {
std::array<int, sizeof...(T)> vect;
template <int ... Is>
Base (std::integer_sequence<int, Is...>) : vect {{ (Is+1)*(Is+1) ... }}
{ }
Base () : Base{std::make_integer_sequence<int, sizeof...(T)>{}}
{ }
};
(2) the first argument of std::apply() isn't compatible with a (non static) method.
But you can wrap it's use in a lambda, so I propose
lastResult = std::apply([=](auto ... args)
{ return this->foo(args...); },
this->vect);
Clarification: This question originally came from a challenge I thought of, and isn't connect with programming for real systems.
Suppose I have a class, that I know its' architecture which I can't change, and I don't want to inherit it, but I do want to get access to its' private data and functions. How can I do it?
Suppose my class looks like this one:
class A {
public:
int v = 89;
private:
int a = 5;
virtual void function(int a, int b) {
cout << a << " " << b << endl;
}
};
a while ago stumbled upon a neat template trick to do this on this blog: http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html
Do NOT use this in any production code, it is just a educational example !!!
it takes basically leverage of the "private" being ignored on some part of template initialization
template<typename Tag>
struct result {
/* export it ... */
typedef typename Tag::type type;
static type ptr;
};
template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;
template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
/* fill it ... */
struct filler {
filler() { result<Tag>::ptr = p; }
};
static filler filler_obj;
};
template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
usage: take following struct:
struct A {
private:
void f() {
std::cout << "proof!" << std::endl;
}
};
create your "robber"
struct Af { typedef void(A::*type)(); };
template class rob<Af, &A::f>;
use it:
int main()
{
A a;
(a.*result<Af>::ptr)();
return 0;
}
A less risky hack will be to make your function/class a friend of the class if you are allowed to modify just the header file.
// Add
class HackA;
class A {
public:
// Add
friend class HackA;
int v = 89;
private:
int a = 5;
virtual void function(int a, int b) {
cout << a << " " << b << endl;
}
};
Now you can use:
class HackA {
public:
int number(A const& a) { return a.v; }
int another_number(A const& a) { return a.a; }
void target_function(A& a, int number, int another_one)
{
a.function(number, another_one);
}
};
int main()
{
A a;
HackA hacker
cout << hacker.number(a) << " " << hacker.another_number(a) << endl;
hacker.target_function(a, 9, 3);
return 0;
}
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";
}
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
I do not think "in place" is the right term, but I am lacking a better one.
I have a POD, let's say:
struct My {
int a;
};
//and suppose a operator<< to stream is also defined
And I may use it right this:
My my = {3};
std::cout << my << std::endl;
I am wondering if I can do the same below but without using a helper func:
template <typename ANY>
My helper(ANY value) {
My r = {value};
return r;
}
std::cout << helper(3) << std::endl;
I am looking for the same thing that a constructor does, but since I have a POD I can not create a constructor.
You can do this:
struct My {
int a;
int b;
int c;
float d;
};
void somefunc() {
cout << (My){1, 2, 3, 4.5} << endl;
}