Re: fighting with move sematics and std::tuple
I added move constructors and much more debugging.
Here's the new FunctionTracker.h source file:
-------------------------------------------------------------
/*
* FunctionTracker.h
*
* Created on: Oct 30, 2011
* 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<>
struct EnterExit
{
std::string _name;
EnterExit(std::string const & name)
:_name(name)
{
std::cerr << _name << ": enter" << std::endl;
};
~EnterExit()
{
std::cerr << _name << ": exit" << std::endl;
};
};
/**
* classify input vs. output parameter
* to log for entering vs. exiting a procedure/function
*/
typedef enum
{
Input_c = 1,
Output_c = 2
} ParamType_t;
/**
* parameter type-independent base class
*/
struct _ArgCommon
{
char const * const _name;
ParamType_t const _type;
_ArgCommon(
char const * const name,
ParamType_t const type)
: _name(name),
_type(type)
{
std::cerr << "_ArgCommon: c'tor" << std::endl;
};
_ArgCommon(_ArgCommon&& rhs)
: _name(rhs._name),
_type(rhs._type)
{
std::cerr << "_ArgCommon: move c'tor" << std::endl;
};
#if 0
// TODO: want to get rid of the copy c'tor
_ArgCommon(_ArgCommon const &) = delete;
#else
_ArgCommon(
_ArgCommon const &rhs)
: _name(rhs._name),
_type(rhs._type)
{
std::cerr << "_ArgCommon copy c'tor" << std::endl;
};
#endif
_ArgCommon & operator=(_ArgCommon const &) = delete;
};
/**
* host class for parameter_name << ": enter" <<
* referencing to the variable
*/
template <typename T>
struct _Arg : public _ArgCommon
{
const T & _value;
_Arg(
char const * const name,
ParamType_t const type,
T const & value)
: _ArgCommon(name, type),
_value(value)
{
std::cerr << "_Arg: c'tor" << std::endl;
};
_Arg(_Arg&& rhs)
: _ArgCommon(std::move(rhs)),
_value(rhs._value)
{
std::cerr << "_Arg: move c'tor" << std::endl;
};
#if 0
// TODO: want to get rid of the copy c'tor
_Arg(_Arg const & rhs) = delete;
#else
_Arg(
_Arg const & rhs)
: _ArgCommon(rhs),
_value(rhs._value)
{
std::cerr << "_Arg: copy c'tor" << std::endl;
};
#endif
_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;
}
/**
* input parameter variant
*/
template <typename T>
struct InArg : public _Arg<T>
{
InArg(
char const * const name,
T const & value)
: _Arg<T>(name, Input_c, value)
{
std::cerr << "InArg: c'tor" << std::endl;
};
// move constructor
InArg(InArg&& rhs)
: _Arg<T>(std::move(rhs))
{
std::cerr << "InArg: move c'tor" << std::endl;
};
#if 0
// TODO: want to get rid of the copy c'tor
InArg(InArg const & rhs) = delete;
#else
InArg(
InArg const & rhs)
: _Arg<T>(rhs)
{
std::cerr << "InArg: copy c'tor" << std::endl;
};
#endif
InArg & operator=(InArg const &) = delete;
};
/**
* output parameter variant
*/
template <typename T>
struct OutArg : public _Arg<T>
{
OutArg(
char const * const name,
T const & value)
: _Arg<T>(name, Output_c, value)
{
std::cerr << "OutArg: c'tor" << std::endl;
};
// move constructor
OutArg(OutArg&& rhs)
: _Arg<T>(std::move(rhs))
{
std::cerr << "OutArg: move c'tor" << std::endl;
};
#if 0
// TODO: want to get rid of the copy c'tor
OutArg(OutArg const & rhs) = delete;
#else
OutArg(
OutArg const & rhs)
: _Arg<T>(rhs)
{
std::cerr << "OutArg: copy c'tor" << std::endl;
};
#endif
OutArg & operator=(OutArg const &) = delete;
};
template <typename T>
InArg<T> MakeInArg(
char const * const name,
T & value)
{
return InArg<T>(name, value);
};
template <typename T>
OutArg<T> MakeOutArg(
char const * const name,
T & value)
{
return OutArg<T>(name, value);
};
// variadic template type list transformation
template <typename ...Types>
struct _ArgTuple
{
typedef typename std::tuple<const _Arg<Types>...> 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 _FunctionTrackerImpl
{
private:
EnterExit _dummy;
char const * const _funcName;
const PARAMS _params;
protected:
_FunctionTrackerImpl(
char const* const funcName,
PARAMS && params)
: _dummy("EnterExit(FunctionTrackerImpl: c'tor MIL"),
_funcName(funcName?funcName:"<unknown>"),
_params(std::move(params))
{
EnterExit dummy("EnterExit(FunctionTrackerImpl: c'tor)");
if (_FunctionTrackerShared::_level > 0) {
std::cerr << std::setw(_FunctionTrackerShared::_level) << ' ';
}
std::cerr << _funcName << ": enter with ";
PrintInput(_params);
std::cerr << std::endl;
++_FunctionTrackerShared::_level;
}
#if 0
_FunctionTrackerImpl(const _FunctionTrackerImpl &) = delete;
#else
_FunctionTrackerImpl(const _FunctionTrackerImpl & rhs)
: _dummy("EnterExit(FunctionTrackerImpl: copy c'tor MIL"),
_funcName(rhs._funcName),
_params(rhs._params)
{
std::cerr << "!!! _FunctionTrackerImpl copy c'tor !!!" <<
std::endl;
}
#endif
~_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 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::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::tuple<Tp...>&
t)
{
const _ArgCommon& arg = std::get<I>(t);
if (paramType == arg._type) {
std::cerr << std::get<I>(t) << ", ";
}
PrintTuple<I + 1, Tp...>(paramType, t);
}
};
/**
* FunctionTracker factory supporting variable arguments
*/
template <typename... Types>
class FunctionTracker : public _FunctionTrackerImpl< typename
_ArgTuple<Types...>::Type >
{
private:
EnterExit _enterExit;
typedef _FunctionTrackerImpl< typename _ArgTuple<Types...>::Type >
BaseType;
typedef typename _ArgTuple<Types...>::Type PARAMS;
FunctionTracker(
char const * const funcName,
PARAMS && params)
: BaseType(funcName, std::move(params)),
_enterExit("EnterExit(FunctionTracker: c'tor MIL)")
{
EnterExit dummy("EnterExit(FunctionTracker: c'tor)");
};
public:
FunctionTracker(const FunctionTracker & rhs)
: BaseType(rhs),
_enterExit("EnterExit(FunctionTracker: copy c'tor MIL)")
{
EnterExit dummy("EnterExit(FunctionTracker: copy c'tor)");
};
FunctionTracker(FunctionTracker && rhs)
: BaseType(std::move(rhs)),
_enterExit("EnterExit(FunctionTracker: move c'tor MIL)")
{
EnterExit dummy("EnterExit(FunctionTracker: move c'tor)");
};
template <typename... Args>
static FunctionTracker make(
char const * const funcName,
Args... args)
{
EnterExit dummy("EnterExit(FunctionTracker::make)");
return FunctionTracker<Types...>(funcName,
std::make_tuple(std::move(args)...));
};
};
#endif /*FUNCTIONTRACKER_H_*/
-------------------------------------------------------------
And here the test main.cpp:
-------------------------------------------------------------
/*
* main.cpp
*
* Created on: Oct 30, 2011
* Author: frank
*/
#include <utility> // std::move<>
#include <functional>
#include "FunctionTracker.h"
int
main(
int argc,
char ** argv)
{
int x = 5;
std::cerr << "### main: create tuple" << std::endl;
std::tuple<InArg<int> > forTest = std::make_tuple(MakeInArg("x", x));
std::cerr << "### main: create FunctionTracker" << std::endl;
auto funcTracker = FunctionTracker<
std::remove_reference<decltype(x)>::type
::make(
__FUNCTION__,
MakeInArg("x", x));
return 0;
}
-------------------------------------------------------------
And this is the output:
-------------------------------------------------------------
frank@frank-desktop:~/workspace/FunctionTracker/Debug$ ./
FunctionTracker
### main: create tuple
_ArgCommon: c'tor
_Arg: c'tor
InArg: c'tor
_ArgCommon: move c'tor
_Arg: move c'tor
InArg: move c'tor
### main: create FunctionTracker
_ArgCommon: c'tor
_Arg: c'tor
InArg: c'tor
EnterExit(FunctionTracker::make): enter
_ArgCommon: move c'tor
_Arg: move c'tor
InArg: move c'tor
_ArgCommon: move c'tor
_Arg: move c'tor
EnterExit(FunctionTrackerImpl: c'tor MIL: enter
_ArgCommon copy c'tor
_Arg: copy c'tor
EnterExit(FunctionTrackerImpl: c'tor): enter
main: enter with input: x => '5',
EnterExit(FunctionTrackerImpl: c'tor): exit
EnterExit(FunctionTracker: c'tor MIL): enter
EnterExit(FunctionTracker: c'tor): enter
EnterExit(FunctionTracker: c'tor): exit
EnterExit(FunctionTracker::make): exit
EnterExit(FunctionTracker: c'tor MIL): exit
main: exit with output:
EnterExit(FunctionTrackerImpl: c'tor MIL: exit
-------------------------------------------------------------
I think first there needs to be avoided the use of the copy c'tor of
FunctionTracker
(and so FunctionTrackerImpl).
But i can't see where this copying comes from(?!)
regards,
Frank
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]