Home C++ Lua GitHub Games Math Myself Contact



C++ Named Parameter Passing
#include <iostream>
#include <string>
#include <map>

using namespace std;

template<typename A, typename B>
std::ostream &operator<<(std::ostream &o, const std::pair<A,B> &p) { return o << "(" << p.first << ", " << p.second << ")"; }

namespace NP {
	template<typename A, typename B>
	struct Comma;
	
	template<typename Param_>
	struct Assign;
}

template<typename A, typename B>
std::ostream &
operator<<(std::ostream &o, const NP::Comma<A,B> &comma);

template<typename T>
std::ostream &
operator<<(std::ostream &o, const NP::Assign<T> &assign);

namespace NP {
	template<typename A, typename B>
	struct Comma {
		A first;
		B second;
		
		//to appease the compiler when trying to pattern-match the base-case:
		typedef void *Value;
		typedef void *Param;

		Comma(const A &first_, const B &second_) 
		: first(first_) , second(second_) {} 

		typename B::Value 
		operator[](const typename B::Param &secondArg) const {
			return second.value;
		}

		template<typename T>
		typename T::Value 
		operator[](const T &firstArg) const {
			return first[firstArg];
		}

		typename A::Value 
		operator[](const typename A::Param &firstArg) const {
			return first.value;
		}
	};
	template<typename Param_>
	struct Assign {
		typedef Param_ Param;
		typedef typename Param::Value Value;
		const Value &value;
		Assign(const Value &value_) : value(value_) {}
	};
}
	
template<typename A, typename B>
std::ostream &
operator<<(std::ostream &o, const NP::Comma<A,B> &comma) {
	return o << comma.first << ", " << comma.second;
}

template<typename T>
std::ostream &
operator<<(std::ostream &o, const NP::Assign<T> &assign) { 
	return o << T::name() << " = " << assign.value;
}

template<typename A, typename B>
NP::Comma<A,B> 
operator,(const A &a, const B &b) {
	return NP::Comma<A,B>(a,b);
}

#define NAMED_PARAM(type__, name__)	\
struct NamedParam_##name__ {	\
	typedef NamedParam_##name__ This;	\
	typedef type__ Value;	\
	static const char *name() { return #name__; } /* used with bundle serialization */	\
	NP::Assign<This> operator=(const Value &v) { return NP::Assign<This>(v); }	\
} name__

namespace bar {
#define COMMA ,
	NAMED_PARAM(pair<double COMMA double>, d);
	//NAMED_PARAM(map<int COMMA double>, e);
	template<typename Args>
	void doo(const Args &args) {
		pair<double,double> d_ = args[d];
		cout << "bar:" << endl;
		cout << "d = " << d_ << endl;
	}
}

namespace foo {
	NAMED_PARAM(const char *, a);
	NAMED_PARAM(double, b);
	NAMED_PARAM(string, c);
	template<typename Args>
	void doo(const Args &args) {
		cout << args << endl;
		const char *a_ = args[a];
		double b_ = args[b];
		string c_ = args[c];
		cout << "foo:" << endl;
		cout << "a = " << a_ << endl;
		cout << "b = " << b_ << endl;
		cout << "c = " << c_ << endl;
		bar::doo(args);
	}
}

int main() {
	using namespace foo;
	using namespace bar;
	foo::doo((
		a = "c-str", 
		b = 2, 
		c = "stl-str",
		d = pair<double,double>(1.0, 2.0)
	));
	return 0;
}


	
Results:
	
a = c-str, b = 2, c = stl-str, d = (1, 2)
foo:
a = c-str
b = 2
c = stl-str
bar:
d = (1, 2)