problem with function calling tracker
Hi,
i want to create some generic function call tracker, which logs enter/
exit of functions plus values of input & output variables for entering
respectively exiting functions.
But i hit a problem to simplify the user interface (see main.cpp).
Here's the code:
--------------------------------------------------- EnterExitMsg.h
---------------------------------------------------------------
/*
* EnterExitMsg.h
*
* Created on: Oct 30, 2011
* Author: frank
*/
#ifndef ENTEREXITMSG_H_
#define ENTEREXITMSG_H_
#include <iostream>
#include <iomanip>
#include <tr1/tuple>
typedef enum
{
Input_c = 1,
Output_c = 2
} ParamType_t;
struct _ArgCommon
{
char const * const _name;
ParamType_t const _type;
_ArgCommon(
char const * const name,
ParamType_t const type)
: _name(name),
_type(type)
{ };
};
template <typename T>
struct _Arg : public _ArgCommon
{
T const & _value;
_Arg(
char const * const name,
ParamType_t const type,
T const & value)
: _ArgCommon(name, type),
_value(value)
{ };
};
template <typename T>
struct InArg : public _Arg<T>
{
InArg(
char const * const name,
T const & value)
: _Arg<T>(name, Input_c, value)
{ };
};
template <typename T>
struct OutArg : public _Arg<T>
{
OutArg(
char const * const name,
T const & value)
: _Arg<T>(name, Output_c, value)
{ };
};
// variadic template type list transformation
template <typename ...Types>
struct _ArgTuple
{
typedef typename std::tr1::tuple<const _Arg<Types>&...> Type;
};
template <typename T>
std::ostream &operator<<(
std::ostream &out,
const _Arg<T> &arg)
{
out << arg._name << " => '" << arg._value << "'";
return out;
}
struct _EnterExitMsgShared {
static int _level;
};
template <typename PARAMS>
class _EnterExitMsgImpl
{
private:
char const * const _funcName;
const PARAMS & _params;
public:
_EnterExitMsgImpl(
char const* const funcName,
const PARAMS & params)
: _funcName(funcName?funcName:"<unknown>"),
_params(params)
{
if (_EnterExitMsgShared::_level > 0) {
std::cerr << std::setw(_EnterExitMsgShared::_level) << ' ';
}
std::cerr << _funcName << ": enter with ";
PrintInput(_params);
std::cerr << std::endl;
++_EnterExitMsgShared::_level;
}
~_EnterExitMsgImpl()
{
--_EnterExitMsgShared::_level;
if (_EnterExitMsgShared::_level > 0) {
std::cerr << std::setw(_EnterExitMsgShared::_level) << ' ';
}
std::cerr << _funcName << ": exit with ";
PrintOutput(_params);
std::cerr << std::endl;
}
void PrintInput(
const PARAMS & params)
{
std::cerr << "input: ";
PrintTuple(Input_c, params);
}
void PrintOutput(
const PARAMS & params)
{
std::cerr << "output: ";
PrintTuple(Output_c, params);
}
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
PrintTuple(ParamType_t const paramType, const
std::tr1::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
PrintTuple(ParamType_t const paramType, const
std::tr1::tuple<Tp...>& t)
{
_ArgCommon arg = std::tr1::get<I>(t);
if (paramType == arg._type) {
std::cerr << std::tr1::get<I>(t) << ", ";
}
PrintTuple<I + 1, Tp...>(paramType, t);
}
};
template <typename... Types>
class EnterExitMsg : public _EnterExitMsgImpl< typename
_ArgTuple<Types...>::Type >
{
private:
typedef typename _ArgTuple<Types...>::Type PARAMS;
EnterExitMsg(
char const * const funcName,
const PARAMS & params)
: _EnterExitMsgImpl<PARAMS>(funcName, params)
{ };
public:
static EnterExitMsg make(
char const * const funcName,
const PARAMS & params)
{
return EnterExitMsg<Types...>(funcName, params);
};
// non-working user-friendly version of 'make'
static EnterExitMsg make2(
char const * const funcName,
const _Arg<Types>&... params)
{
return EnterExitMsg<Types...>(funcName,
std::tr1::make_tuple(params...));
};
};
#endif /*ENTEREXITMSG_H_*/
-------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------- EnterExitMsg.cpp
------------------------------------------------------------
/*
* EnterExitMsg.cpp
*
* Created on: Nov 1, 2011
* Author: frank
*/
#include "EnterExitMsg.h"
int _EnterExitMsgShared::_level = 0;
-------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------- main.cpp
-------------------------------------------------------------------------
/*
* main.cpp
*
* Created on: Oct 30, 2011
* Author: frank
*/
#include <memory> // std::auto_ptr<>
#include <iostream>
#include <tr1/tuple>
#include "EnterExitMsg.h"
#define DEBUG
int ThirdLevelProcedure(
int const & inp1,
char const * const inp2)
{
int retVal = 3;
#ifdef DEBUG
auto enterExitMsg = EnterExitMsg<int, char const * const, int>::make(
__FUNCTION__,
std::tr1::make_tuple(
InArg<int>("inp1", inp1),
InArg<char const * const>("inp2", inp2),
OutArg<int>("retVal", retVal)));
#endif
std::cerr << "\thello, from ThirdLevelProcedure()" << std::endl;
return retVal;
}
int SecondLevelProcedure(void)
{
int retVal = 2;
#ifdef DEBUG
auto enterExitMsg = EnterExitMsg<int>::make(
__FUNCTION__,
std::tr1::make_tuple(
OutArg<int>("retVal", retVal)));
#endif
#if 0
auto enterExitMsg = EnterExitMsg<int>::make2(
__FUNCTION__,
OutArg<int>("retVal", retVal));
#endif
std::cerr << "\thello, from SecondLevelProcedure()" << std::endl;
ThirdLevelProcedure(5, "calling ThirdLevelProcedure()");
return retVal;
}
int FirstLevelProcedure(
char const * const inp1)
{
int retVal = 1;
#ifdef DEBUG
auto enterExitMsg = EnterExitMsg<char const * const, int>::make(
__FUNCTION__,
std::tr1::make_tuple(
InArg<char const * const>("inp1", inp1),
OutArg<int>("retVal", retVal)));
#endif
std::cerr << "\thello, from FirstLevelProcedure()" << std::endl;
SecondLevelProcedure();
return retVal;
}
int main(
int argc,
char ** argv)
{
FirstLevelProcedure("calling FirstLevelProcedure()");
// SecondLevelProcedure();
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------------------
The output should be:
FirstLevelProcedure: enter with input: inp1 => 'calling
FirstLevelProcedure()',
hello, from FirstLevelProcedure()
SecondLevelProcedure: enter with input:
hello, from SecondLevelProcedure()
ThirdLevelProcedure: enter with input: inp1 => '5', inp2 => 'calling
ThirdLevelProcedure()',
hello, from ThirdLevelProcedure()
ThirdLevelProcedure: exit with output: retVal => '3',
SecondLevelProcedure: exit with output: retVal => '2',
FirstLevelProcedure: exit with output: retVal => '1',
But when i turn on the 'make2' version for SecondLevelProcedure(...),
then it prints:
FirstLevelProcedure: enter with input: inp1 => 'calling
FirstLevelProcedure()',
hello, from FirstLevelProcedure()
SecondLevelProcedure: enter with input:
hello, from SecondLevelProcedure()
ThirdLevelProcedure: enter with input: inp1 => '5', inp2 => 'calling
ThirdLevelProcedure()',
hello, from ThirdLevelProcedure()
ThirdLevelProcedure: exit with output: retVal => '3',
SecondLevelProcedure: exit with output:
Btw, i am sure, there is more stuff odd about it, that needs to be
cleaned up.
But for now, i am focusing why i can't make work 'make2'.
- thanks!
regards,
Frank
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]