A method utilizing variadic arguments and variadic macros is presented which permits the simple generation of a string of any method name and of its arguments from within that method.
Introduction
If you need to obtain a string
of a method name and of its arguments perhaps when throwing std::invalid_argument
, variadic arguments and variadic macros make it easy to do so. The procedure presented here requires arguments of class type accept operator <<
shown below.
operator << (basic_ostream<char>&, const class type&)
The code which generates the string
of the class and method name and its argument type names and their values is shown below:
#include <sstream>
using namespace std;
template <typename First> string args_to_string(const First& first)
{
char space = ' ';
ostringstream oss;
oss << typeid(first).name() << space << first;
return oss.str();
}
template <typename First, typename... Rest> _
string args_to_string(const First& first, const Rest&... rest)
{
char space = ' ';
char comma = ',';
ostringstream oss;
oss << typeid(first).name() << space << first;
oss << comma << space;
oss << args_to_string(rest...); return oss.str();
}
#define CLASSSTRING string(typeid(*this).name())
#define CLASSMETHODSTRING CLASSSTRING + string("::") + string(__func__)
#define ARGSSTRING(...) string("(") + args_to_string(__VA_ARGS__) + string(")")
#define CLASSMETHODARGSSTRING(...) CLASSMETHODSTRING + ARGSSTRING(__VA_ARGS__)
Only...
CLASSMETHODARGSSTRING(arg1, etc.)
...needs to be inserted into your code as shown below:
#include <above code in manner you prefer>
#include <iostream>
#include <stdexcept>
template<class T>
class cgoobar {
T m_x;
public:
cgoobar() : m_x(0) {}
template<typename charT>
friend
basic_ostream<charT>& operator << (basic_ostream<charT>& os, const cgoobar& gb)
{
os << gb.m_x;
return os;
}
};
template<class T>
class cfoobar
{
public:
template<class T, class U>
void foobar(T x, U y) { if (!x) throw invalid_argument(CLASSMETHODARGSSTRING(x, y)); }
};
int main()
{
cfoobar<int> fb;
cgoobar<double> gb;
try { fb.foobar(0, gb); }
catch (const invalid_argument& ex) { cout << ex.what(); }
}
The output of the code demonstrating its correctness as it was thrown by the indicated method with the indicated arguments is:
class cfoobar<int>::foobar(int 0, class cgoobar<double> 0)
History
- 4th May, 2020: Initial version