struct P {
int x, y;
friend P operator-(P u, P v) { return {u.x - v.x, u.y - v.y}; }
friend int cross(P u, P v) { return u.x * v.y - u.y * v.x; }
int cross(P u, P v) const { return cross(u - *this, v - *this); }
};
The method is an infinite loop (it will call itself instead of the friend).
Is there any way to get around this issue without changing the interface (the names)?
It is possible with a declaration inside the member function:
#include <stdio.h>
struct Foo {
friend int add(int a, int b) {
return a + b;
}
int add(int a, int b) const {
int add(int, int); // function declaration
return add(a, b); // call that declared function
}
};
int main() {
Foo foo;
printf("%d", foo.add(1, 2)); // prints 3
}
Demo
You can't have two member functions with the same name and the same signature in a struct (or class).
One solution is to move the friend function out of the struct, so that it can be referred to with a global namespace specifier ::
#include <iostream>
int cross(int i) { return 42; }
struct P {
friend int cross(int i);
int cross(int i) const { return ::cross(i - 1); }
};
int main() {
P p = {};
std::cout << p.cross(7) << std::endl;
}
The original code produced two warnings, very descriptive:
1 > 1.cpp(6, 25) : warning C4514 : 'cross' : unreferenced inline function has been removed
1 > 1.cpp(7) : warning C4717 : 'P::cross' : recursive on all control paths, function will cause runtime stack overflow
Re: without changing the interface (the names) - you could simply rename your friend function and even make it private; it is not a part of the interface.
Ayxan Haqverdili's answer seems to be cleanest possible, and abides by the ISO. However, pre-gcc 11.0 and pre-clang 8.0 appear to have bugs that cause this to fail.
Luckily in this case there's an alternative that uses argument-dependent lookup:
#include <iostream>
class Foo
{
friend int Bar (Foo)
{
return 13;
}
friend int RedirectToBar (Foo);
public:
int Bar (Foo)
{
return RedirectToBar(Foo());
}
};
int RedirectToBar (Foo)
{
return Bar(Foo());
}
int main ()
{
std::cout << Foo().Bar(Foo()) << std::endl;
}
Live demo
Keep in mind that this only works because some of the arguments to the function are an associated class.
If that's not the case and you really want to keep this design and really need compatibility with older compilers, then we can add in a dummy associated class without breaking the interface by adding it as a default parameter:
#include <iostream>
int RedirectToBar ();
class Foo
{
struct Key {};
friend int Bar (Key = Key())
{
return 13;
}
friend int RedirectToBar ();
public:
int Bar ()
{
return RedirectToBar();
}
};
int RedirectToBar ()
{
return Bar(Foo::Key());
}
int main ()
{
std::cout << Foo().Bar() << std::endl;
}
Live demo
However, it's important to add that all of this is a big code smell. Although I don't know the real-world problem of the OP, this seems like a terrible hack to get around bad design choices.
I ended up using this solution similar to Peter's and Yksisarvinen's:
struct P {
int x, y;
friend P operator-(P u, P v) { return P{u.x - v.x, u.y - v.y}; }
friend int cross(P u, P v);
int cross(P u, P v) const;
};
int cross(P u, P v) { return u.x * v.y - u.y * v.x; }
int P::cross(P u, P v) const { return ::cross(u - *this, v - *this); }
Not quite sure yet why the compiler doesn't find ::cross if I write it inside of P.
Note, there is one potential drawback: we have to specify the return type of both functions (can't have it deduced with auto), but this was not needed in this case.
Related
My code is as follows:
class Foo{
public:
int operator()(int i)
{
return 1;
}
int operator++(int i)
{
return 1;
}
};
int main()
{
Foo foo;
int a = foo++;
int b = foo(0);
float c = 0;
}
The problem is that I am not able to watch foo(0):
foo++ is visible normally.
I think the reason is that overloaded function call operator becomes a FunctionObject type (see here https://en.cppreference.com/w/cpp/language/operators).
Is it possible to watch it?
As n-1-8e9-wheres-my-share-m commented, foo.operator()(0) works for me:
I'm working on an NES emulator in c++ and figured that the most efficient way to run opcodes would be to call a function pointer in an array of functions that do exactly what the opcode does.
The problem is that each opcode has a specific operation and memory address. While searching for a solution, I stumbled upon lambda expressions. This is definitely good enough for a NES emulator on modern hardware. However, I can't find a solution such that each function in the array contains the machine code for both the operation and the addressing without defining 256 separate functions.
This is along what I had in mind for a similar function that combines f and g:
int addone(int x) {
return x + 1;
}
int multtwo(int x) {
return 2 * x;
}
something combine(function<int(int)> f, function <int(int)> g) {
/* code here */
}
/*
combine(addone, multtwo) creates a function h that has the same machine code as
int h(x) {
return 2 * x + 1;
}
*/
Any ideas? If I had to take a guess, it would have something to do with templates. Thanks!
I'd say that when you want to write generics for functions that it's kind of a "design pattern" to switch to functors: Compilers are desigined to handle types easily, but handling function pointers for stuff you want to mis-match and keep optimised at compile-time gets ugly!
So we either write our functions as functors, or we wrap them as functors:
struct A
{
static constexpr int Func (int x)
{
return -3*x + 1;
}
};
struct B
{
static constexpr int Func (int x)
{
return -2*x - 5;
}
};
// etc...
If we have nice symmetry in how we'll use them, then we can manage them systematically. Eg. if we always want to combine them like f(g(h(...y(z())...))), then we can solve as follows:
template <class T, class ... Ts>
struct Combine
{
static constexpr int Get ()
{
int x = Combine<Ts...>::Get();
return T::Func(x);
}
};
template <class T>
struct Combine <T> // The base case: the last function in the list
{
static constexpr int Get ()
{
return T::Func();
}
};
demo
Or if we're in no such luck, we'll have to resort to more old-fashioned inputs like you suggested:
template <class Funcs, class Data>
constexpr int Combine (const Data & d)
{
Funcs F;
// Some use without much symmetry:
return F.f(F.g(d)) - F.h(d);
}
int main ()
{
struct FuncArgs
{
A f;
B g;
C h;
};
return Combine<FuncArgs>(5);
}
demo
Note that in the second example I've changed from static methods to non-static. This doesn't really matter - the compiler should optimise these fully regardless, but I think in this case it makes the syntax slightly nicer (and shows an alternative style).
You can do something like this, using a lambda to capture the two functions and to assign a function to a variable:
#include <functional>
#include <iostream>
int addone(int x){
return x + 1;
}
int multtwo(int x){
return x * 2;
}
std::function<int(int)> combine(std::function<int(int)> f, std::function<int(int)> g){
auto tmp = [&](int x){ return f(g(x)); };
return std::function<int(int)>(tmp);
}
int main(){
auto h = combine(std::function<int(int)>(addone), std::function<int(int)>(multtwo)); // (2 * x) + 1
std::cout << h(10); // Prints 21
}
If you want it to generally combine the functions, you can use a template:
#include <functional>
#include <iostream>
int addone(int x){
return x + 1;
}
int multtwo(int x){
return x * 2;
}
template <typename Func>
std::function<Func> combine(std::function<Func> f, std::function<Func> g){
auto tmp = [&](int x){ return f(g(x)); };
return std::function<Func>(tmp);
}
int main(){
auto h = combine<int(int)>(std::function<int(int)>(addone), std::function<int(int)>(multtwo));
std::cout << h(10) << "\n"; // Prints 21
}
You also don't need to specify the type, since the compiler can figure it out:
#include <functional>
#include <iostream>
int addone(int x){
return x + 1;
}
int multtwo(int x){
return x * 2;
}
template <typename func>
std::function<Func> combine(std::function<Func> f, std::function<Func> g){
auto tmp = [&](int x){ return f(g(x)); };
return std::function<Func>(tmp);
}
int main(){
auto h = combine(std::function<int(int)>(addone), std::function<int(int)>(multtwo));
std::cout << h(10) << "\n"; // Still prints 21
}
We can use templates to create a generic compose function that "combines" two unary functions using a lambda that captures the functions passed in, and returns it.
#include <functional>
#include <iostream>
template <typename Input, typename Output1, typename Output2>
std::function<Output2(Input)> compose(
std::function<Output2(Output1)> f,
std::function<Output1(Input)> g
) {
return [&f, &g](Input x) { return f(g(x)); };
}
int foo(int x) {
return x + 1;
}
int bar(int x) {
return x * 2;
}
int main() {
auto baz = compose<int, int, int>(foo, bar);
std::cout << baz(5) << std::endl;
auto wooble = compose<int, int, float>(
[](int x) { return static_cast<float>(x) + 1.5; },
[](int x) { return x * 3; }
);
std::cout << wooble(5) << std::endl;
return 0;
}
Do you want this?
int f1(int x) { return x + 1; }
int f2(int x) { return x * 2; }
int f3(int x) { return x * 3; }
int f4(int x) { return x - 5; }
int f5(int x) { return x + 9; }
int main() {
auto cf = combine<int>(f1, f2, f3, f4, f5);
std::cout << cf(5) << std::endl;
return 0;
}
Output:
40
Full code:
#include <functional>
#include <concepts>
#include <iostream>
template<typename T, typename NUM = int>
concept num_processor = requires (T t, NUM x) {
{t(x)} -> std::same_as<NUM>;
};
template<typename NUM, num_processor p>
NUM process(NUM v, p proc) {
return proc(v);
}
template<typename NUM, num_processor p, num_processor... Funs>
NUM process(NUM v, p proc, Funs... funs) {
return process(proc(v), funs...);
}
template<typename NUM, num_processor... Funs>
std::function<NUM (NUM)> combine(Funs... funs) {
return [...funs = funs] (NUM v) { return process(v, funs...); };
}
int f1(int x) { return x + 1; }
int f2(int x) { return x * 2; }
int f3(int x) { return x * 3; }
int f4(int x) { return x - 5; }
int f5(int x) { return x + 9; }
int main() {
auto cf = combine<int>(f1, f2, f3, f4, f5);
std::cout << cf(5) << std::endl;
return 0;
}
Compile with
-std=c++20 for gcc and /std:c++latest for msvc
Most other answers suggest std::function, but I'm wary of the runtime overhead it requires.
Since you don't need to select which functions are composed at runtime, you can do it without it. I'm using the same idea as #Elliot, but generalized for arbitrary types, and with hopefully nicer syntax:
#include <iostream>
#include <utility>
template <auto F0, auto ...F>
struct FuncList
{
static constexpr auto first = F0;
static constexpr bool have_next = true;
using next = FuncList<F...>;
};
template <auto F0>
struct FuncList<F0>
{
static constexpr auto first = F0;
static constexpr bool have_next = false;
};
template <typename F, typename ...P>
decltype(auto) Combine(P ...params) // Normally there would be `&&`, but I removed it allow casting to any function pointer type.
{
if constexpr (F::have_next)
return F::first(Combine<typename F::next, P &&...>(std::forward<P>(params)...));
else
return F::first(std::forward<P>(params)...);
}
int addone(int x)
{
return x + 1;
}
int multtwo(int x)
{
return 2 * x;
}
int main()
{
int (*ptr)(int) = Combine<FuncList<addone, multtwo>>;
std::cout << ptr(10) << '\n'; // 21
}
If you want to create automatically the functions, use 2pichar's answer with a for loop, but for an emulator you'd probably want something like opcode->int(*)(int). This could be done by some tree-like structure:
std::map<char, naive_opcode> opcodes;
struct naive_opcode {
std::map<char, naive_opcode> next;
int(* opcode_func)(int);
};
You'd work through this in some fashion like:
char data;
buf >> data;
naive_opcode opcode = opcodes[data];
while(!opcode.opcode_func){
buf >> data;
opcode = opcode.next[data];
}
opcode.opcode_func(param);
This of course ignores errors and does not include things like the instruction pointer and the .text section memory, rather replacing it with the buf buffer for illustrative purposes (In a real life example I'd expect this to be replaced by data=memory[ip]; ++ip;). This could then be combined with an implementation like:
#include <iostream>
int addone(int x){
return x + 1;
}
int multtwo(int x){
return x * 2;
}
template<int(* F)(int), int(* G)(int)>
int combined(int x){
return F(G(x));
}
int main(){
std::cout << combined<addone,multtwo>(10);
}
for which you could essentially just define the end node of naive_opcode as {{}, combined<addone,multtwo>}.
Unfortunately as I mentioned in my comment, this probably cannot be done automatically. The best you could do I recon is that you define something like:
std::vector<std::pair<const char*, int(*)(int)>> raw_opcodes = {{"\x10\x13", addone}, ...};
and then parse that into the tree like structure. As a brief side note: this might not be needed if all the opcodes are 1 byte (which I am unsure about since I am not familiar with NES). Then a simple std::map<char,int(*)(int)> opcodes will suffice instead of the convoluted naive_opcode (or better tree) implementation.
Looked it up and it seems that you wouldn't need the tree implementation, but a modification like this can be useful:
template<int(* F)(int)>
int combined(int x){
return F(x);
}
template<int(* F)(int), int(* A)(int), int(*... G)(int)>
int combined(int x){
return F(combined<A, G...>(x));
}
This allows for combining many effects into each other, rather than 2.
I feel like this question must have been asked before but I couldn't find an answer from poking around on google. If it has please direct me to a link and I will remove this post.
Consider this minimal example that represents a larger problem I have. Say I created a simple "Point" and "Printer" class like so:
class Point {
public:
double x, y;
Point() {x = y = 0;}
Point(double x, double y) {
this->x = x; this->y = y;
}
};
template<typename T>
class Printer {
public:
T* mData;
int mSize;
// Constructor
Printer(std::vector<T> &input) {
mData = &input[0];
mSize = input.size();
}
// Simple Print function
void Print() {
printf(" - Showing %d items\n", mSize);
for (int i = 0; i < mSize; i++) {
const T &item = mData[i];
printf(" - Item %d: (%lf, %lf)\n", i, item.x, item.y);
}
}
};
I could use the printer class like this:
std::vector<Point> points; // fill the vector, and then...
Printer<Point> pointsPrinter(points); pointsPrinter.Print();
Now say someone else comes along and wants to use the Printer class with there own "Point" class declared like so:
class Pnt {
public:
double mX, mY;
// other stuff
};
If they try to do this:
vector<Pnt> pnts; // Fill the pnts, and then...
Printer<Pnt> pntsPrinter(pnts);
pntsPrinter.Print(); // COMPILE ERROR HERE!
Obviously this will fail because Pnt has no x or y members. Does there exist a way I can rewrite the Printer class to work with all generic user types? What I DONT want to do is copy a Pnt vector into a Points vector.
EDIT:
The only way I can think to make this work would be to pass in functions pointers. Something like this:
template<typename T>
class Printer {
public:
T* mData;
int mSize;
double* (*mXFunc) (T*);
double* (*mYFunc) (T*);
Printer(std::vector<T> &input,
double* (*xFunc) (T*),
double* (*yFunc) (T*))
{
mData = &input[0];
mSize = input.size();
mXFunc = xFunc;
mYFunc = yFunc;
}
void Print() {
printf(" - Showing %d items\n", mSize);
for (int i = 0; i < mSize; i++) {
T &item = mData[i];
printf(" - Item %d: (%lf, %lf)\n", i, *mXFunc(&item), *mYFunc(&item));
}
}
};
// Could then use it like so
inline double* getXPointVal(Point *point) {return &point->x;}
inline double* getYPointVal(Point *point) {return &point->y;}
inline double* getXPntVal(Pnt *point) {return &point->mX;}
inline double* getYPntVal(Pnt *point) {return &point->mY;}
Printer<Pnt> pntPrinter(pnts, getXPntVal, getYPntVal);
Printer<Point> pointsPrinter(points, getXPointVal, getYPointVal);
pntPrinter.Print();
pointsPrinter.Print();
The problem with this is that it looks ugly and also possibly introduces the function call overhead. But I guess the function call overhead would get compiled away? I was hoping a more elegant solution existed...
If you choose cout instead of printf to write your output, you can allow all printable types to define an overload for the << operator and use that generically inside Printer::print(). An overload could look like this:
std::ostream& operator<<(std::ostream &out, Point& p){
out << "Point(" << p.x << ", " << p.y << ")";
return out;
}
On a side note, I advise against storing a pointer to a vector's internal storage and size member. If the vector needs to reallocate, your pointer will be left dangling and invalid. Instead, you should pass the vector temporarily as a reference or keep a const reference.
You could define free (non-member) functions for each Point class you want to use. The advantage of this is that free functions can be defined later, without making changes to existing classes.
Example:
namespace A {
class Point {
public:
Point (int x, int y) : x_(x), y_(y) {}
int getX () const { return x_; }
int getY () const { return y_; }
private:
int x_, y_;
};
// in addition, we provide free functions
int getX (Point const & p) { return p.getX(); }
int getY (Point const & p) { return p.getY(); }
}
namespace B {
class Pnt {
public:
Pnt (int x, int y) : x_(x), y_(y) {}
int get_x () const { return x_; }
int get_y () const { return y_; }
private:
int x_, y_;
};
// Pnt does not have free functions, and suppose we
// do not want to add anything in namespace B
}
namespace PointHelpers {
// free functions for Pnt
int getX (Pnt const & p) { return p.get_x (); }
int getY (Pnt const & p) { return p.get_y (); }
}
// now we can write
template <class PointTy>
void printPoint (PointTy const & p) {
using PointHelpers::getX;
using PointHelpers::getY;
std::cout << getX (p) << "/" << getY (p) << std::endl;
}
A::Point p1 (2,3);
B::Pnt p2 (4,5);
printPoint (p1);
printPoint (p2);
If the free functions live in the same namespace as the corresponding class, they will be found by argument-dependent name lookup. If you do not want to add anything in that namespace, create a helper namespace and add the free functions there. Then bring them into scope by using declarations.
This approach is similar to what the STL does for begin and end, for instance.
Don't expect from the templates to know which members of given class/structure corresponds to your x and y...
If you want to create generic solution you could tell your printer function how to interpret given object as your Point class using e.g. lambda expression (c++11 solution):
#include <iostream>
class Point {
public:
double x, y;
Point() {x = y = 0;}
Point(double x, double y) {
this->x = x; this->y = y;
}
};
class Pnt {
public:
double mX, mY;
// other stuff
};
template <class P, class L>
void Print(const P &p, L l) {
Print(l(p));
}
void Print(const Point &p) {
std::cout << p.x << ", " << p.y << std::endl;
}
int main() {
Print(Point(1, 2));
Print(Pnt{4, 5}, [](const Pnt &p) -> Point {return Point(p.mX, p.mY);});
}
I am attaching the code here and explaining the problem below:
Here is the class Bitop:
#ifndef _Bitop_H
#define _Bitop_H
# include <iostream>
double num2fxp(double v, int bits=9, int intbits=5){
return -0.5;
}
template<int bits = 8, int intbits = 6>
class Bitop
{
template<int rhsbits, int rhsintbits> friend class Bitop;
private:
double value; // data value
public:
Bitop(const double& v=0):
value(num2fxp(v, bits, intbits))
{}
template<int rhsbits, int rhsintbits>
const Bitop<bits, intbits>& operator = (const Bitop<rhsbits, rhsintbits>& v){
value = num2fxp(v.value, bits, intbits);
return *this;
}
template<int rhsbits, int rhsintbits>
Bitop<bits, intbits>& operator += (const Bitop<rhsbits, rhsintbits>& v) {
value = num2fxp(value+v.value, bits, intbits);
return *this;
}
template<int lhsbits, int lhsintbits, int rhsbits, int rhsintbits>
friend Bitop<lhsintbits+rhsintbits+2, lhsintbits+rhsintbits+1> operator + (const Bitop<lhsbits, lhsintbits>& x, const Bitop<rhsbits, rhsintbits>& y){
return Bitop<lhsintbits+rhsintbits+2, lhsintbits+rhsintbits+1> (num2fxp(x.value+y.value));
}
friend std::ostream& operator<< (std::ostream & out, const Bitop& y){return out << y.value ;}
void Print(){
std::cout << value<< "<"
<< bits << ","
<< intbits << ">";
}
};
#endif
And the Test function:
# include <iostream>
# include "Bitop.H"
using namespace std;
int main (int argc, char** argv) {
Bitop<4,1> a = 0.8;
Bitop<5,2> b(3.57);
Bitop<7,3> c;
c = b;
cout << "See all attributes of c \n";
c.Print();cout << "\n";
c = 7.86;
cout << "reassign c to a new value\n";
c.Print();cout << "\n";
cout << "set b = c \n";
b = c;
b.Print();cout<<"\n";
cout << "set b+=a \n";
b += a;
b.Print();cout<<"\n";
cout << "set b=c+a \n";
b = c+a;
b.Print();cout<<"\n";
return 0;
}
I have a templated class Bitop. I want to overload "+" to add 2 objects with different template parameters and return a third object with parameters different from the rhs and lhs objects, i.e. I want to do the following:
Bitop<5,3> + Bitop<4,2> should return Bitop<10,6>. I declared Bitop to be a friend class of itself so I can access the private members of rhs and lhs objects. But I am getting compilation error (due to redefinition) regardless of whether I call the "+" function.
I am not clear about what I am doing wrong here. Any help is appreciated.
Please note that I left a couple of functions and function calls in the code to ensure that other overloads such as = and += work correctly.
Here's a simplified example that shows the same problem:
template<int i>
struct X {
template<int a, int b>
friend void foo(X<a>, X<b>) { }
};
int main()
{
X<1> x1;
X<4> x2; // error: redefinition of foo
}
Every time a new specialization of X gets instantiated, the definition of foo is inserted in the scope sorounding the template class X. I hope it's clear where the error is coming from.
Things would be different if the declaration depended on template parameter of the class, like:
template<int i>
struct X {
template<int a, int b>
friend void foo(X<a+i>, X<b+i>) { } // different definiton
// for each specialization of X
};
The solution is to define the friend function outside of class:
template<int i>
struct X {
template<int a, int b>
friend void foo(X<a>, X<b>);
};
template<int a, int b>
void foo(X<a>, X<b>) { }
int main()
{
X<1> x1;
X<4> x2;
}
You don't really need to define operator+ as friend:
template<int I>
class A
{
double X;
template<int> friend class A;
public:
A(A const&) = default;
A(double x)
: X(x) {}
template<int J>
A(A<J> const&a)
: X(a.X) {}
template<int J>
A<I+J> operator+ (A<J> const&a)
{ return A<I+J>(X+a.X); }
};
int main()
{
A<0> a0(3);
A<1> a1(4);
auto ax = a0+a1;
}
Moreover, the result returned by operator+(a,b) should really be identical to that obtained by operator=(a) followed by operator+=(b).
It's possible to define a pointer to a member and using this later on:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int foo::* aptr=&foo::a;
bar.a=1;
std::cout << bar.*aptr << std::endl;
}
Now I need to have a pointer to a specific element of an array, so normally I'd write
int foo::* bptr=&(foo::b[0]);
However, the compiler just complains about an "invalid use of non-static data member 'foo::b'"
Is it possible to do this at all (or at least without unions)?
Edit: I need a pointer to a specific element of an array, so int foo::* ptr points to the second element of the array (foo::b[1]).
Yet another edit: I need to access the element in the array by bar.*ptr=2, as the pointer gets used somewhere else, so it can't be called with bar.*ptr[1]=2 or *ptr=2.
However, the compiler just complains about an "invalid use of non-static data member 'foo::b'"
This is because foo::a and foo::b have different types. More specifically, foo::b is an array of size 2 of ints. Your pointer declaration has to be compatible i.e:
int (foo::*aptr)[2]=&foo::b;
Is it possible to do this at all (or at least without unions)?
Yes, see below:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int (foo::*aptr)[2]=&foo::b;
/* this is a plain int pointer */
int *bptr=&((bar.*aptr)[1]);
bar.a=1;
bar.b[0] = 2;
bar.b[1] = 11;
std::cout << (bar.*aptr)[1] << std::endl;
std::cout << *bptr << std::endl;
}
Updated post with OP's requirements.
The problem is that, accessing an item in an array is another level of indirection from accessing a plain int. If that array was a pointer instead you wouldn't expect to be able to access the int through a member pointer.
struct foo
{
int a;
int *b;
};
int main()
{
foo bar;
int foo::* aptr=&(*foo::b); // You can't do this either!
bar.a=1;
std::cout << bar.*aptr << std::endl;
}
What you can do is define member functions that return the int you want:
struct foo
{
int a;
int *b;
int c[2];
int &GetA() { return a; } // changed to return references so you can modify the values
int &Getb() { return *b; }
template <int index>
int &GetC() { return c[index]; }
};
typedef long &(Test::*IntAccessor)();
void SetValue(foo &f, IntAccessor ptr, int newValue)
{
cout << "Value before: " << f.*ptr();
f.*ptr() = newValue;
cout << "Value after: " << f.*ptr();
}
int main()
{
IntAccessor aptr=&foo::GetA;
IntAccessor bptr=&foo::GetB;
IntAccessor cptr=&foo::GetC<1>;
int local;
foo bar;
bar.a=1;
bar.b = &local;
bar.c[1] = 2;
SetValue(bar, aptr, 2);
SetValue(bar, bptr, 3);
SetValue(bar, cptr, 4);
SetValue(bar, &foo::GetC<0>, 5);
}
Then you at least have a consistent interface to allow you to change different values for foo.
2020 update, with actual solution:
The Standard does currently not specify any way to actually work with the member pointers in a way that would allow arithmetics or anything to get the pointer to the "inner" array element
OTOH, the standard library now has all the necessities to patch the appropriate member pointer class yourself, even with the array element access.
First, the member pointers are usually implemented as "just offsets", although quite scary. Let's see an example (on g++9, arch amd64):
struct S { int a; float b[10]; };
float(S::*mptr)[10] = &S::b;
*reinterpret_cast<uintptr_t *>(&mptr) //this is 4
int S::*iptr = &S::a;
*reinterpret_cast<uintptr_t *>(&iptr) //this is 0
iptr = nullptr;
*reinterpret_cast<uintptr_t *>(&iptr) //this seems to be 18446744073709551615 on my box
Instead you can make a bit of a wrapper (it's quite long but I didn't want to remove the convenience operators):
#include <type_traits>
template<class M, typename T>
class member_ptr
{
size_t off_;
public:
member_ptr() : off_(0) {}
member_ptr(size_t offset) : off_(offset) {}
/* member access */
friend const T& operator->*(const M* a, const member_ptr<M, T>& p)
{ return (*a)->*p; }
friend T& operator->*(M* a, const member_ptr<M, T>& p)
{ return (*a)->*p; }
/* operator.* cannot be overloaded, so just take the arrow again */
friend const T& operator->*(const M& a, const member_ptr<M, T>& p)
{ return *reinterpret_cast<const T*>(reinterpret_cast<const char*>(&a) + p.off_); }
friend T& operator->*(M& a, const member_ptr<M, T>& p)
{ return *reinterpret_cast<T*>(reinterpret_cast<char*>(&a) + p.off_); }
/* convert array access to array element access */
member_ptr<M, typename std::remove_extent<T>::type> operator*() const
{ return member_ptr<M, typename std::remove_extent<T>::type>(off_); }
/* the same with offset right away */
member_ptr<M, typename std::remove_extent<T>::type> operator[](size_t offset) const
{ return member_ptr<M, typename std::remove_extent<T>::type>(off_)+offset; }
/* some operators */
member_ptr& operator++()
{ off_ += sizeof(T); return *this; };
member_ptr& operator--()
{ off_ -= sizeof(T); return *this; };
member_ptr operator++(int)
{ member_ptr copy; off_ += sizeof(T); return copy; };
member_ptr operator--(int)
{ member_ptr copy; off_ -= sizeof(T); return copy; };
member_ptr& operator+=(size_t offset)
{ off_ += offset * sizeof(T); return *this; }
member_ptr& operator-=(size_t offset)
{ off_ -= offset * sizeof(T); return *this; }
member_ptr operator+(size_t offset) const
{ auto copy = *this; copy += offset; return copy; }
member_ptr operator-(size_t offset) const
{ auto copy = *this; copy -= offset; return copy; }
size_t offset() const { return off_; }
};
template<class M, typename T>
member_ptr<M, T> make_member_ptr(T M::*a)
{ return member_ptr<M, T>(reinterpret_cast<uintptr_t>(&(((M*)nullptr)->*a)));}
Now we can make the pointer to the array element directly:
auto mp = make_member_ptr(&S::b)[2];
S s;
s->*mp = 123.4;
// s.b[2] is now expectably 123.4
Finally, if you really, really like materialized references, you may get a bit haskell-lensish and make them compose:
// in class member_ptr, note transitivity of types M -> T -> TT:
template<class TT>
member_ptr<M,TT> operator+(const member_ptr<T,TT>&t)
{ return member_ptr<M,TT>(off_ + t.offset()); }
// test:
struct A { int a; };
struct B { A arr[10]; };
B x;
auto p = make_member_ptr(&B::arr)[5] + make_member_ptr(&A::a)
x->*p = 432.1;
// x.arr[5].a is now expectably 432.1
typedef int (foo::*b_member_ptr)[2];
b_member_ptr c= &foo::b;
all works.
small trick for member and function pointers usage.
try to write
char c = &foo::b; // or any other function or member pointer
and in compiller error you will see expected type, for your case int (foo::*)[2].
EDIT
I'm not sure that what you want is legal without this pointer. For add 1 offset to your pointer you should get pointer on array from your pointer on member array. But you can dereference member pointer without this.
You can't do that out of the language itself. But you can with boost. Bind a functor to some element of that array and assign it to a boost::function:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
struct test {
int array[3];
};
int main() {
namespace lmb = boost::lambda;
// create functor that returns test::array[1]
boost::function<int&(test&)> f;
f = lmb::bind(&test::array, lmb::_1)[1];
test t = {{ 11, 22, 33 }};
std::cout << f(t) << std::endl; // 22
f(t) = 44;
std::cout << t.array[1] << std::endl; // 44
}
I'm not sure if this will work for you or not, but I wanted to do a similar thing and got around it by approaching the problem from another direction. In my class I had several objects that I wanted to be accessible via a named identifier or iterated over in a loop. Instead of creating member pointers to the objects somewhere in the array, I simply declared all of the objects individually and created a static array of member pointers to the objects.
Like so:
struct obj
{
int somestuff;
double someotherstuff;
};
class foo
{
public:
obj apples;
obj bananas;
obj oranges;
static obj foo::* fruit[3];
void bar();
};
obj foo::* foo::fruit[3] = { &foo::apples, &foo::bananas, &foo::oranges };
void foo::bar()
{
apples.somestuff = 0;
(this->*(fruit[0])).somestuff = 5;
if( apples.somestuff != 5 )
{
// fail!
}
else
{
// success!
}
}
int main()
{
foo blee;
blee.bar();
return 0;
}
It seems to work for me. I hope that helps.