[any] Multimethod for boost::any and modified boost::any to fit multi method

Hi All. I create multi method for boost::any using Modern C++ Design's multi method technique. It can dispatch method dynamically like this: _________________________________________________________________________ struct T1 { string operator()(int value) const { return string("T1(int)"); }; string operator()(double value) const { return string("T1(double)"); }; string operator()(A value) const { return string("T1(A)"); }; }; // "entry" to Multi method bool t10(Multimethod::entry<any, any, T1, int>()); bool t11(Multimethod::entry<any, any, T1, double>()); bool t12(Multimethod::entry<any, any, T1, A>()); struct T2 { string operator()(int value) const { return string("T2(int)"); }; }; // "entry" to Multi method bool t20(Multimethod::entry<any, any, T2, int>()); BOOST_AUTO_TEST_CASE(test04) { any m((T1())); any a(0); BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T1(int)"); a = 0.0; BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T1(double)"); a = A(); BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T1(A)"); m = T2(); a = 0; BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T2(int)"); }; __________________________________________________________________________ If you are interested in this multi method, please see #2749 for detail. https://svn.boost.org/trac/boost/ticket/2749 Thanks, Nowake

nowake@fiercewinds.net wrote:
I create multi method for boost::any using Modern C++ Design's multi method technique.
It can dispatch method dynamically like this: _________________________________________________________________________ struct T1 { string operator()(int value) const { return string("T1(int)"); }; string operator()(double value) const { return string("T1(double)"); }; string operator()(A value) const { return string("T1(A)"); }; }; // "entry" to Multi method bool t10(Multimethod::entry<any, any, T1, int>()); bool t11(Multimethod::entry<any, any, T1, double>()); bool t12(Multimethod::entry<any, any, T1, A>());
struct T2 { string operator()(int value) const { return string("T2(int)"); }; }; // "entry" to Multi method bool t20(Multimethod::entry<any, any, T2, int>());
BOOST_AUTO_TEST_CASE(test04) { any m((T1())); any a(0); BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T1(int)"); a = 0.0; BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T1(double)"); a = A(); BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T1(A)");
m = T2(); a = 0; BOOST_CHECK_EQUAL( any_cast<string>(Multimethod::apply<any>(m, a)), "T2(int)"); };
This looks overcomplicated. A while ago, I offered something like this any m = 0; apply_visitor<int, double, A>(f, m); or alternatively, apply_visitor(f, m); with f specifying all overloads in some compile-time reflection structure. unfortunately, it cannot be made constant-time because std::type_info sucks. Is your solution constant-time?

Is your solution constant-time?
No. It cannot dispatch constant-time with boost::any. So I make "Holder" class to dispatch constant-time. Holder is similar to boost::any, but it have "id" method that can return unique integer from each content type. And Multimethod can dispatch method in constant-time using this "id" integer. Regards. Nowake

Mathias Gaunard wrote:
A while ago, I offered something like this
any m = 0; apply_visitor<int, double, A>(f, m);
or alternatively, apply_visitor(f, m); with f specifying all overloads in some compile-time reflection structure.
unfortunately, it cannot be made constant-time because std::type_info sucks.
FWIW, I would be really interested in this feature even if it's not constant time. May I hope it will appear in trunk one day?

A while ago, I offered something like this FWIW, I would be really interested in this feature even if it's not constant time. May I hope it will appear in trunk one day?
Me too. I want to know how you treat; - return value type - argument combination (especially const volatile) - terrible std::type_info Regards. Nowake

Andrey Semashev wrote:
Mathias Gaunard wrote:
A while ago, I offered something like this
any m = 0; apply_visitor<int, double, A>(f, m);
or alternatively, apply_visitor(f, m); with f specifying all overloads in some compile-time reflection structure.
unfortunately, it cannot be made constant-time because std::type_info sucks.
FWIW, I would be really interested in this feature even if it's not constant time. May I hope it will appear in trunk one day?
It can actually be made constant-time using the result of std::type_info::name for dispatching. That means, however, that you need to know as a compile-time string the names of the types to check for, and have implemented a compile-time name mangling algorithm (which is of course platform-specific).

Mathias Gaunard wrote:
Andrey Semashev wrote:
Mathias Gaunard wrote:
A while ago, I offered something like this
any m = 0; apply_visitor<int, double, A>(f, m);
or alternatively, apply_visitor(f, m); with f specifying all overloads in some compile-time reflection structure.
unfortunately, it cannot be made constant-time because std::type_info sucks.
FWIW, I would be really interested in this feature even if it's not constant time. May I hope it will appear in trunk one day?
It can actually be made constant-time using the result of std::type_info::name for dispatching. That means, however, that you need to know as a compile-time string the names of the types to check for, and have implemented a compile-time name mangling algorithm (which is of course platform-specific).
That looks like too much of a burden for users, let alone the portability issues. I think the implementation that provides the interface you mentioned above would be more suitable, even if slower. I don't think that people will often try to dispatch between hundreds or even tens of types, where the difference would matter.

I update Multimethod that use boost::unorderd_map. Currently, Multimethod dispatches method in constant-time. https://svn.boost.org/trac/boost/ticket/2749 (Multimethod.2.hpp) ...but I cannot measure difference between std::map and boost::unorderd_map. I think handreds classes are too few to measure it. Regards. Nowake

I update Multimethod that use boost::unorderd_map. Currently, Multimethod dispatches method in constant-time.
I made a mistake. I didn't know that std::type_info instance is not unique in a program. I had to change boost::any::type and boost::any::holder::type like this; __________________________________________________________ template<typename ValueType> static const std::type_info& any::typeinfo() { static const std::type_info& r(typeid(ValueType)); return r; } const std::type_info & any::type() const { return content ? content->type() : typeinfo<void>(); //return content ? content->type() : typeid(void); } template<typename ValueType> virtual const std::type_info& boost::any::holder<ValueType>::type() const { return typeinfo<ValueType>(); //return typeid(ValueType); } __________________________________________________________ It's necessary to change boost::any to implement multimethod dispatching in constant-time. Regards. Nowake

Hi everyone. I update Multimethod to enhance flexibility of return value. https://svn.boost.org/trac/boost/attachment/ticket/2749/Multimethod.3.hpp Now, I can modify return value without changing the function objects. ______________________________________________________________________ // Multimethod's return value's traits // specialize template class in shared_ptr<any> (return type) template<> struct Multimethod::ReturnTraits<shared_ptr<any> > { template<typename from_t> static shared_ptr<any> result(from_t& value) { return shared_ptr<any>(new any(value)); }; template<typename from_t> static shared_ptr<any> result(const from_t& value) { return shared_ptr<any>(new any(value)); }; // specialize template function in shared_ptr<any> // If target function object's return value is shared_ptr<any>, // Multimethod::apply returns value directly. template<> static shared_ptr<any> result<shared_ptr<any> >(shared_ptr<any>& value) { return value; }; template<> static shared_ptr<any> result<shared_ptr<any> >(const shared_ptr<any>& value) { return value; }; }; struct TestAnyMethod0 { // Multi method string operator()() const { return string("string()"); }; string operator()(int value) const { return string("string(int)"); }; shared_ptr<any> operator()(double value) const { return shared_ptr<any>( new any(string("shared_ptr<any>(string(double))"))); }; }; bool m00(Multimethod::entry<shared_ptr<any>, any, TestAnyMethod0>()); bool m01(Multimethod::entry<shared_ptr<any>, any, TestAnyMethod0, int>()); bool m02(Multimethod::entry<shared_ptr<any>, any, TestAnyMethod0, double>()); TestAnyMethod0 m; any mm(m); // Multimethod::apply fits TestAnyMethod0's return value // to shared_ptr<any> using Multimethod::ReturnTraits::result. shared_ptr<any> r(Multimethod::apply<shared_ptr<any> >(mm)); BOOST_CHECK_EQUAL(any_cast<string>(*r), "string()"); any a0(0); r = Multimethod::apply<shared_ptr<any> >(mm, a0); BOOST_CHECK_EQUAL(any_cast<string>(*r), "string(int)"); any a1(0.0); r = Multimethod::apply<shared_ptr<any> >(mm, a1); BOOST_CHECK_EQUAL(any_cast<string>(*r), "shared_ptr<any>(string(double))"); // r's content is not shared_ptr<any>. // Multimethod::apply return shared_ptr<any> directly. ______________________________________________________________________ Regards. Nowake

Hi, I update Multimethod. I make Multimethod::ApplyTraits to control method's dispatching. https://svn.boost.org/trac/boost/attachment/ticket/2749/Multimethod.4.hpp Samples: ______________________________________________________________________ struct Method10 { // MultiMethod string operator()(const int a) const { return string("int: "+lexical_cast<string>(a)); }; string operator()(const double a) const { return string("double: "+lexical_cast<string>(a)); }; }; struct Method11 : public Method10 {}; struct Apply10 { // ApplyTraits to change int <-> double template<typename A00> string operator()(A00& a00, const double a01) { return a00(static_cast<int>(a01)); }; template<typename A00> string operator()(A00& a00, const int a01) { return a00(static_cast<double>(a01)); }; }; // you can set ApplyTraits to each type combination. // custom ApplyTraits bool m10(Multimethod::entry<string, any, Method10, const int>(Apply10())); bool m11(Multimethod::entry<string, any, Method10, const double>(Apply10())); // use default ApplyTraits bool m12(Multimethod::entry<string, any, Method11, const int>()); bool m13(Multimethod::entry<string, any, Method11, const double>()); BOOST_AUTO_TEST_CASE(test01) { Method10 m10; any mm(m10); BOOST_CHECK_EQUAL(Multimethod::apply<string>(mm, 1), "double: 1"); BOOST_CHECK_EQUAL(Multimethod::apply<string>(mm, 1.0), "int: 1"); Method11 m11; mm = m11; BOOST_CHECK_EQUAL(Multimethod::apply<string>(mm, 1), "int: 1"); BOOST_CHECK_EQUAL(Multimethod::apply<string>(mm, 1.0), "double: 1"); } // you can also use ApplyTraits to fit functions to multi methods. struct Method00 { // MultiMethod string operator()() const { return string("string()"); }; }; struct Apply00 { // ApplyTraits template<typename A00> shared_ptr<any> operator()(A00& a00) { return shared_ptr<any>(new any(a00())); }; }; // entry Method00::operator()() with ApplyTraits bool m00(Multimethod::entry<shared_ptr<any>, any, Method00>(Apply00())); BOOST_AUTO_TEST_CASE(test00) { Method00 m; any mm(m); shared_ptr<any> r(Multimethod::apply<shared_ptr<any> >(mm)); BOOST_CHECK_EQUAL(any_cast<string>(*r), "string()"); } _____________________________________________________________________ Regrads. Nowake
participants (4)
-
Andrey Semashev
-
Mathias Gaunard
-
Nowake
-
nowakeï¼ fiercewinds.net