Re: problem with function calling tracker
It works (somehow).
But i have still a problem.
I can't disable copy c'tor for class ArgCommon and the classes derived
from it
(prepared but disabled in code below).
However, actually the object to track (function argument) is not
copied - already know.
So it might not be needed to disable copy c'tor for ArgCommon and
derived classes(?!)
Can you help me, please?
- many thanks!
Here is the latest version
(For you convenience, you can download tgz with Makefile from here:
http://frank-bergemann.jimdo.com/programming/c/functiontracker/
at the bottom of the page)
----------------------------------- FunctionTracker.h
------------------------------------
/*
* FunctionTracker.h
*
* Created on: Oct 30, 2011
* Author: frank
*/
#ifndef __FUNCTION_TRACKER_H__
#define __FUNCTION_TRACKER_H__
#include <iostream>
#include <iomanip>
#include <utility> // std::forward<>
#include <tr1/tuple> // std::tr1::tuple<>
/*
* TODO:
* +) use namespace
* +) hide internal definitions from user
* +) do w/o FunctionTracker.cpp
* +) don't directly log to std::cerr
* option: static FunctionTracker::Setup to pass stream? (functor?)
*/
/**
* function parameter type (in, out, inout)
*/
typedef enum
{
In_c = 1,
Out_c = 2,
InOut_c = In_c | Out_c
} ParamType_t;
/**
* non-template base class for function parameters
*/
struct ArgCommon
{
char const * const _name;
ParamType_t const _type;
ArgCommon(
char const * const name,
ParamType_t const type)
: _name(name),
_type(type)
{ };
// ArgCommon(const ArgCommon & rhs) = delete;
};
/**
* template'd function parameter class
* extending ArgCommon
*/
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)
{ };
// Arg(const Arg & rhs) = delete;
};
/*
* Abbreviations for IN, OUT & INOUT parameter
*/
/**
* IN parameter
*/
template <typename T>
struct InArg : public Arg<T>
{
InArg(
char const * const name,
T const & value)
: Arg<T>(name, In_c, value)
{ };
// InArg(const InArg & rhs) = delete;
};
/**
* OUT parameter
*/
template <typename T>
struct OutArg : public Arg<T>
{
OutArg(
char const * const name,
T const & value)
: Arg<T>(name, Out_c, value)
{ };
// OutArg(const OutArg & rhs) = delete;
};
/**
* INOUT parameter
*/
template <typename T>
struct InOutArg : public Arg<T>
{
InOutArg(
char const * const name,
T const & value)
: Arg<T>(name, InOut_c, value)
{ };
InOutArg(const InOutArg & rhs) = delete;
};
// variadic template type list transformation
template <typename ...Types>
struct ArgTuple
{
/*
* TODO: this implies copying of the args!
* But the version to use references doesn't work!
*/
#if 0
typedef typename std::tr1::tuple<const Arg<Types>&...> Type;
#endif
typedef typename std::tr1::tuple<const Arg<Types>...> Type;
ArgTuple(const ArgTuple & rhs) = delete;
};
/**
* ostream helper for function paramter
* supposes ostream helper for the parameter type is avail
*/
template <typename T>
std::ostream &operator<<(
std::ostream &out,
const Arg<T> &arg)
{
out << arg._name << " => '" << arg._value << "'";
return out;
}
struct FunctionTrackerShared {
static int _level;
};
template <typename ParamTuple>
class FunctionTrackerImpl
{
private:
char const * const _funcName;
/*
* TODO:
* This implies copying
* Try to do with const reference (rvalue reference?)
* But the version to use references doesn't work!
*/
#if 0
const ParamTuple & _params;
#endif
const ParamTuple _params;
protected:
FunctionTrackerImpl(
char const* const funcName,
ParamTuple && params)
: _funcName(funcName?funcName:"<unknown>"),
_params(std::forward<ParamTuple>(params))
{
if (FunctionTrackerShared::_level > 0) {
std::cerr << std::setw(FunctionTrackerShared::_level) << ' ';
}
std::cerr << _funcName << ": enter with ";
PrintInput(_params);
std::cerr << std::endl;
++FunctionTrackerShared::_level;
}
FunctionTrackerImpl(const FunctionTrackerImpl & rhs)
: _funcName(rhs._funcName),
_params(rhs._params)
{
std::cerr << "!!! _EnterExitMsgImpl copy c'tor !!!" << std::endl;
}
~FunctionTrackerImpl()
{
--FunctionTrackerShared::_level;
if (FunctionTrackerShared::_level > 0) {
std::cerr << std::setw(FunctionTrackerShared::_level) << ' ';
}
std::cerr << _funcName << ": exit with ";
PrintOutput(_params);
std::cerr << std::endl;
}
void PrintInput(
const ParamTuple & params)
{
std::cerr << "input: ";
PrintTuple(In_c, params);
}
void PrintOutput(
const ParamTuple & params)
{
std::cerr << "output: ";
PrintTuple(Out_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 FunctionTracker : public FunctionTrackerImpl< typename
ArgTuple<Types...>::Type >
{
private:
typedef FunctionTrackerImpl< typename ArgTuple<Types...>::Type >
BaseType;
typedef typename ArgTuple<Types...>::Type ParamTuple;
FunctionTracker(
char const * const funcName,
ParamTuple && params)
: FunctionTrackerImpl<ParamTuple>(funcName,
std::forward<ParamTuple>(params))
{ };
public:
FunctionTracker(const FunctionTracker & rhs)
: BaseType(rhs)
{ };
template <typename... Args>
static FunctionTracker make(
char const * const funcName,
Args&&... args)
{
return FunctionTracker<Types...>(funcName,
std::tr1::make_tuple(std::forward<Args>(args)...));
};
};
#endif /*__FUNCTION_TRACKER_H__*/
-----------------------------------------------------------------------------------------------
--------------------------------- FunctionTracker.cpp
-----------------------------------------
/*
* FunctionTracker.cpp
*
* Created on: Nov 1, 2011
* Author: frank
*/
#include "FunctionTracker.h"
int FunctionTrackerShared::_level = 0;
-----------------------------------------------------------------------------------------------
--------------------------------- FunctionTrackerTest.cpp
-------------------------------------
/*
* FunctionTrackerTest.cpp
*
* Created on: Oct 30, 2011
* Author: frank
*/
#include <iostream>
#include <stdexcept>
#include "FunctionTracker.h"
#define DEBUG
/*
* a test class to check, if EnterExitMsg
* does unwanted copying or given arguments
*/
class TestClass
{
public:
TestClass()
{};
~TestClass()
{};
TestClass(
const TestClass & rhs)
{
std::cerr << "!!! TestClass copy c'tor invoked !!!" << std::endl;
};
};
std::ostream &
operator<<(
std::ostream & out,
const TestClass & arg)
{
out << "TestClass";
return out;
}
int
ForthLevelProcedure(
char const * const inp)
{
int retVal = 4711;
bool normalExit = false;
#ifdef DEBUG
auto enterExitMsg = FunctionTracker<char const * const, int,
bool>::make(
__FUNCTION__,
InArg<char const * const>("inp", inp),
OutArg<int>("retVal", retVal),
OutArg<bool>("normalExit", normalExit)
);
#endif
throw std::runtime_error("hello");
normalExit = true;
return retVal;
}
int
ThirdLevelProcedure(
int const & inp1,
char const * const inp2,
const TestClass & tc1,
const TestClass & tc2)
{
int retVal = 3;
bool normalExit = 0;
#ifdef DEBUG
auto enterExitMsg = FunctionTracker<int, char const * const,
TestClass, TestClass, int, bool>::make(
__FUNCTION__,
std::forward<InArg<int>>(InArg<int>("inp1", inp1)),
std::forward<InArg<char const * const>>(InArg<char const *
const>("inp2", inp2)),
std::forward<InArg<TestClass>>(InArg<TestClass>("tc1", tc1)),
std::forward<InArg<TestClass>>(InArg<TestClass>("tc2", tc2)),
std::forward<OutArg<int>>(OutArg<int>("retVal", retVal)),
std::forward<OutArg<bool>>(OutArg<bool>("normalExit", normalExit)));
#endif
std::cerr << "\thello, from ThirdLevelProcedure()" << std::endl;
// check for throwing function called
try {
ForthLevelProcedure("calling ForthLevelProcedure()");
}
catch(...) {
std::cerr << "!!! caught exception from
ForthLevelProcedure(...) !!!" << std::endl;
}
normalExit = true;
return retVal;
}
int
SecondLevelProcedure(
void)
{
int retVal = 2;
#ifdef DEBUG
auto enterExitMsg = FunctionTracker<int>::make(
__FUNCTION__,
std::forward<OutArg<int>>(OutArg<int>("retVal", retVal)));
#endif
std::cerr << "\thello, from SecondLevelProcedure()" << std::endl;
TestClass tc;
ThirdLevelProcedure(5, "calling ThirdLevelProcedure()", tc,
TestClass());
return retVal;
}
int
FirstLevelProcedure(
char const * const inp1)
{
int retVal = 1;
#ifdef DEBUG
auto functionTracker = FunctionTracker<char const * const,
int>::make(
__FUNCTION__,
std::forward<InArg<char const * const>>(InArg<char const *
const>("inp1", inp1)),
std::forward<OutArg<int>>(OutArg<int>("retVal", retVal)));
#endif
std::cerr << "\thello, from FirstLevelProcedure()" << std::endl;
SecondLevelProcedure();
return retVal;
}
int
main(
int argc,
char ** argv)
{
FirstLevelProcedure("calling FirstLevelProcedure()");
#if 0
std::cerr << std::endl;
SecondLevelProcedure();
#endif
return 0;
}
-----------------------------------------------------------------------------------------------
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]