// Copyright David Abrahams 2003. Use, modification and distribution is // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include namespace test { namespace mpl = boost::mpl; template struct keyword; template struct get_keyword { get_keyword(const Default& x) : default_(x) {} const Default& default_; }; struct nil { template struct apply { typedef nil type; }; template struct apply_value { typedef const Default& type; }; template static D const& get(D const& x) { return x; } template nil const& value(D const& x) const { return *this; } template const nil& operator()(const T& x) const { return *this; } template const Default& operator[](const get_keyword& x) const { return x.default_; } }; // A tuple of labeled argument holders template struct list : H, T { list(H h, T t) : H(h), T(t) {} template struct apply : mpl::apply_if< boost::is_same , mpl::identity , typename T::template apply > {}; template struct apply_value : mpl::apply_if< boost::is_same , mpl::identity , typename T::template apply_value > {}; template typename apply::type const& value(K) const { return boost::implicit_cast< typename apply::type const& >(*this); } template list > operator,(const list& x) const { return list >(x, *this); } const list& operator,(nil) const { return *this; } template typename apply_value::type operator[](const get_keyword& x) const { return value(K()).get(x.default_); } template typename apply_value::type operator[](const keyword&) const { return value(K()).get(); } }; template list cons(H const& h, T const& t) { return list(h,t); } struct named_base {}; template struct named : named_base { typedef KW key_type; typedef T value_type; typedef T& ref_type; named(T& x) : value(x) {} template T& get( Default const& ) const { return value; } T& get() const { return value; } T& value; }; template struct keyword { template named operator=(T& x) const { return named(x); } template named operator=(T const& x) const { return named(x); } template list, nil> operator()(const T& x) const { return list, nil>( named(x), nil()); } template list, nil> operator()(T& x) const { return list, nil>( named(x), nil()); } template list, nil> operator()(const named& x) const { return list, nil>( x, nil()); } nil operator()(nil) const { return nil(); } template get_keyword operator|(const Default& default_) { return get_keyword(default_); } }; // // Add labels to arguments that may have been passed positionally. // Why the help with function ordering is required is completely // beyond me. // template named label_positional_arg(T const& x, ...) { return named(x); } template named label_positional_arg(T& x, char) { return named(x); } template named const& label_positional_arg(named const& x, int) { return x; } // ------------ end of named param library code ------------- // // keyword declarations. PP generatable, of course // struct name_t : keyword { using keyword::operator=; } name; struct value_t : keyword { using keyword::operator=; } value; struct index_t : keyword { using keyword::operator=; } index; // // core function implementation // // // f overloads for various #s of args. This could be avoided somewhat // by using f((kw1 = v1, kw2 = v2)) and overloading operator, but // there would be other disadvantages, like an inability to handle two // initial positional args. This boilerplate can probably be // generated with the PP. // // Some reduction might be achieved by successively currying single // arguments and calling the next overload, if the cons lists were // built backwards. // // Generates boilerplate code template struct named_param_fun { R operator()() const { return (*this)(nil()); } template R operator()(const A0& a0) const { return (*this)(a0, nil()); } template R operator()(const A0& a0, const A1& a1) const { return (*this)(a0, a1, nil()); } template R operator()(const A0& a0, const A1& a1, const A2& a2) const { return (*this)(a0, a1, a2, nil()); } template R operator()(const A0& a0, const A1& a1, const A2& a2, const A3& a3) const { K0 k0; K1 k1; K2 k2; K3 k3; return static_cast(*this).call( (k0(a0), k1(a1), k2(a2), k3(a3))); } }; // f() implementation struct f_impl : named_param_fun { template int call(const Params& p) const { std::cout << "-------- f --------" << std::endl; std::cout << "name = " << p[name | "unnamed"] << std::endl; std::cout << "value = " << p[value | 666.222] << std::endl; std::cout << "index = " << p[index | 999] << std::endl; return 1; } } f; // // Just like f, but no default for name // template int g_impl(Params const& p) { std::cout << "-------- g --------" << std::endl; // name has no default std::cout << "name = " << p[name] << std::endl; std::cout << "value = " << p[value | 666.222] << std::endl; std::cout << "index = " << p[index | 999] << std::endl; return 1; } template int g(Name const& name_) { return g(name_, nil(), nil()); } template int g(Name const& name_, Value const& value_) { return g(name_, value_, nil()); } template int g(Name const& name_, Value const& value_, Index const& index_) { return g_impl((name(name_), value(value_), index(index_))); } int x1 = f("x", 3.14, 22); int x2 = f(value = 3.14, name = "x"); int x3 = f(value = 6.5); int x4 = f(); int x5 = g("x", 3.14, 22); int x6 = g(value = 3.14, name = "x"); // g has no default for name, so this call fails // int x7 = g(value = 6.5); int x8 = g("q", index = 77); } int main() { return 0; }