Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Generating a String of a Method Name and of its Arguments in C++

5.00/5 (8 votes)
4 May 2020CPOL 5K  
Method utilizing variadic arguments and macros
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.

C++
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:

C++
#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...); // recursive call using pack expansion syntax
	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...

C++
CLASSMETHODARGSSTRING(arg1, etc.)

...needs to be inserted into your code as shown below:

C++
#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:

C++
class cfoobar<int>::foobar(int 0, class cgoobar<double> 0)

History

  • 4th May, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)