Re: Access Data Items In Ancestor Stack Frames Safely (Dr.Dobb's article)
{ Please format your article properly; don't use a separate line for
each sentence -mod }
I could generalize it a bit - pls. see below.
But it's still very odd.
The goal is to have minimum requirements for user to create a
compatible function
(Func1_Impl<>, Func2_Impl<>, Func3_Impl<>).
And factor out everything else into some include file.
So next is to get rid of Func1<>, Func2<>, Func3<> - or to cut them
back to the essentials.
They are pretty much the same - so they should be one implementation
for all of them.
Preferable to make obsolete the need for wrapper functions inside:
exec_impl and GetCaller()
(i guess this results from my improper use of multiple inheritance).
Another tough thing is:
How to derive a template parameter for variable arguments of the
exec_impl(...) functions
in Func1_Impl<>, Func2_Impl<>, Func3_Impl<>?
Is there something similar to decltype() for this?
best regards,
Frank
============================ StackAccess.h
=================================
#ifndef STACKACCESS_H_
#define STACKACCESS_H_
struct Nop
{
};
template <typename CALLER>
struct Func_Impl
{
CALLER * caller;
CALLER* & GetCaller(void)
{
return caller;
}
};
template <typename CALLER, typename RETURN_TYPE, typename... ARGS>
struct Func
{
virtual CALLER * & GetCaller(void) = 0;
virtual RETURN_TYPE exec_impl(ARGS...) = 0;
virtual ~Func() { }
RETURN_TYPE exec(
CALLER * p_caller, ARGS... args)
{
GetCaller() = p_caller;
return exec_impl(args...);
}
};
#endif /* STACKACCESS_H_ */
====================== main.cpp
=======================================
#include <iostream>
#include "StackAccess.h"
template <typename CALLER>
struct Func3_Impl : public Func_Impl<CALLER>
{
typedef Func3_Impl type;
void exec_impl(void)
{
std::cout << "Func3: entered" << std::endl;
std::cout << "caller->x = "
<< this->caller->x << std::endl;
std::cout << "caller->caller->x = "
<< this->caller->caller->x
<< std::endl;
}
};
template <class CALLER>
struct Func3 : public Func3_Impl<CALLER>,
public Func<
CALLER,
decltype(Func3_Impl<CALLER>().exec_impl())>
{
typedef decltype(Func3_Impl<CALLER>().exec_impl())
return_type;
inline return_type exec_impl(void)
{
return Func3_Impl<CALLER>::exec_impl();
}
inline CALLER * & GetCaller(void)
{
return Func_Impl<CALLER>::GetCaller();
}
};
template <typename CALLER>
struct Func2_Impl : public Func_Impl<CALLER>
{
typedef Func2_Impl type;
int x;
int exec_impl (int p_val)
{
std::cout << "Func2: entered" << std::endl;
std::cout << "p_val = " << p_val << std::endl;
std::cout << "caller->x = " << this->caller->x << std::endl;
this->caller->x = 5;
Func3<type>().exec(this);
return 7;
}
};
template <class CALLER>
struct Func2 : public Func2_Impl<CALLER>,
public Func<
CALLER,
decltype(Func2_Impl<CALLER>().exec_impl(int())),
int> // TODO: how to handle variable arguments?
{
typedef decltype(Func2_Impl<CALLER>().exec_impl(int()))
return_type;
inline return_type exec_impl(
int p_val) // TODO: want to be generic here too
{
return Func2_Impl<CALLER>::exec_impl(p_val);
}
inline CALLER * & GetCaller(void)
{
return Func_Impl<CALLER>::GetCaller();
}
};
template <typename CALLER>
struct Func1_Impl : public Func_Impl<CALLER>
{
typedef Func1_Impl type;
int x;
void exec_impl (void)
{
std::cout << "Func1: entered" << std::endl;
int getVal = Func2<type>().exec(this, 5);
std::cout << "Func2 returns #" << getVal
<< ", x = " << x << std::endl;
}
};
template <class CALLER>
struct Func1 : public Func1_Impl<CALLER>,
public Func<
CALLER,
decltype(Func1_Impl<CALLER>().exec_impl())>
{
public:
typedef decltype(Func1_Impl<CALLER>().exec_impl())
return_type;
inline return_type exec_impl(void)
{
return Func1_Impl<CALLER>::exec_impl();
}
inline CALLER * & GetCaller(void)
{
return Func_Impl<CALLER>::GetCaller();
}
};
int main(
int argc,
char ** argv)
{
Nop nop;
Func1<Nop>().exec(&nop);
return 0;
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]