Re: fighting with move sematics and std::tuple
{ Although this post contains a lot of code and no explanatory
content, it is accepted because it appears to conclude this thread.
When following up, please keep in mind that according to the group's
website, articles containing excessive code are rejected -mod }
This one is much better.
FunctionTracker.h:
----------------------------------------------------------
/*
* FunctionTracker.h
*
* Created on: May 28, 2012
* Author: frank
*/
#ifndef FUNCTIONTRACKER_H_
#define FUNCTIONTRACKER_H_
#include <string>
#include <iostream>
#include <iomanip> // std::setw
#include <utility> // std::forward<>
#include <tuple> // std::tuple<>
#include <type_traits> // std::enable_if<>
#include <stdexcept> // std::runtime_error
namespace FT // FunctionTracker
{
/**
* parameter type-independent base class
*/
struct ArgCommon
{
/**
* classify input vs. output parameter
* to log for entering vs. exiting a procedure/function
*/
typedef enum
{
Input_c = 1,
Output_c = 2
} ParamType_t;
char const * const name;
ParamType_t const type;
ArgCommon(
char const * const name,
ParamType_t const type)
: name(name),
type(type)
{ };
ArgCommon(ArgCommon&& rhs)
: name(rhs.name),
type(rhs.type)
{ };
ArgCommon(
ArgCommon const &rhs)
: name(rhs.name),
type(rhs.type)
{
throw std::runtime_error("ArgCommon: invalid invocation of copy
c'tor");
};
ArgCommon & operator=(ArgCommon const &) = delete;
};
/**
* host class for parameter_name << ": enter" <<
* referencing to the variable
*/
template <typename T>
struct Arg : public ArgCommon
{
typedef T Type;
typedef typename std::remove_reference<T>::type NoRef;
const NoRef & value;
Arg(
char const * const name,
ArgCommon::ParamType_t const type,
T const & value)
: ArgCommon(name, type),
value(value)
{ };
Arg(Arg&& rhs)
: ArgCommon(std::move(rhs)),
value(rhs.value)
{ };
Arg(
Arg const & rhs)
: ArgCommon(rhs), // will throw
value(rhs.value)
{ };
Arg & operator=(Arg const &) = delete;
};
/**
* ostream helper for Arg<T>
*/
template <typename T>
std::ostream &operator<<(
std::ostream &out,
const Arg<T> &arg)
{
out << arg.name << " => '" << arg.value << "'";
return out;
}
template <typename T>
Arg<T> MakeInArg(
char const * const name,
T & value)
{
return Arg<T>(name, ArgCommon::Input_c, value);
};
template <typename T>
Arg<T> MakeOutArg(
char const * const name,
T & value)
{
return Arg<T>(name, ArgCommon::Output_c, value);
};
// variadic template type list (get base types from IN/OUT Args)
template <typename ...Types>
struct TypeTuple
{
typedef typename std::tuple<typename Arg<Types>::Type...> Type;
};
/**
* shared recursion level
* (does not support threads!)
*/
struct FunctionTrackerShared {
static int level;
};
/**
* FunctionTracker implementation
* but not used directly
* 'FunctionTracker' is used instead
*/
template <typename PARAMS>
class FunctionTracker
{
private:
char const * const funcName;
const PARAMS params;
public:
FunctionTracker(
char const* const funcName,
PARAMS && params)
: funcName(funcName?funcName:"<unknown>"),
params(std::move(params))
{
if (FunctionTrackerShared::level > 0) {
std::cerr << std::setw(FunctionTrackerShared::level) << ' ';
}
std::cerr << funcName << ": enter with input: ";
PrintTuple(ArgCommon::Input_c, params);
std::cerr << std::endl;
++FunctionTrackerShared::level;
}
FunctionTracker(const FunctionTracker & rhs)
: funcName(rhs.funcName),
params(rhs.params)
{
throw std::runtime_error("FunctionTrackerImpl: invalid invocation
of copy c'tor");
}
FunctionTracker & operator=(const FunctionTracker &rhs) = delete;
~FunctionTracker()
{
--FunctionTrackerShared::level;
if (FunctionTrackerShared::level > 0) {
std::cerr << std::setw(FunctionTrackerShared::level) << ' ';
}
std::cerr << funcName << ": exit with output: ";
PrintTuple(ArgCommon::Output_c, params);
std::cerr << std::endl;
}
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
PrintTuple(ArgCommon::ParamType_t const & paramType, const
std::tuple<Tp...>& t)
{ }
// TODO: turn dynamic checks into compile time evaluation
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
PrintTuple(ArgCommon::ParamType_t const & paramType, const
std::tuple<Tp...>& t)
{
const ArgCommon& arg = std::get<I>(t);
if (paramType == arg.type) {
std::cerr << std::get<I>(t);
if (I+1!=sizeof...(Tp)) std::cerr << ", ";
}
PrintTuple<I + 1, Tp...>(paramType, t);
}
};
template <typename... Types>
FunctionTracker<typename TypeTuple<Types...>::Type> make(
char const * const funcName,
Types... args)
{
return FunctionTracker<typename TypeTuple<Types...>::Type>(funcName,
std::make_tuple(std::move(args)...));
};
} // namespace FT
#endif /*FUNCTIONTRACKER_H_*/
----------------------------------------------------------
FunctionTracker.cpp:
----------------------------------------------------------
/*
* FunctionTracker.cpp
*
* Created on: May 28, 2012
* Author: frank
*/
#include "FunctionTracker.h"
int FT::FunctionTrackerShared::level = 0;
----------------------------------------------------------
main.cpp:
----------------------------------------------------------
/*
* main.cpp
*
* Created on: Oct 30, 2011
* Author: frank
*/
#include <utility>
#include "FunctionTracker.h"
int
main(
int argc,
char ** argv)
{
int x = 5;
auto funcTracker = FT::make(
__func__,
FT::MakeInArg("x", x));
return 0;
}
----------------------------------------------------------
output:
----------------------------------------------------------
frank@frank-desktop:~/workspace/FunctionTracker/Debug$ ./
FunctionTracker
main: enter with input: x => '5'
main: exit with output:
----------------------------------------------------------
rgds,
Frank
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]