More flexible any_cast for boost::any

Hello, I've been looking at ABIs and such (various unpleasant reasons). But I recently created the following code: #include <iostream> struct Base { virtual void check() = 0; template<typename T> T* IsDerivedFrom() { try { check(); } catch(T* p) { return p; } catch(...) { return nullptr; } return nullptr; } }; template<typename T> struct Derived : public Base { Derived(T obj) : t(obj) {} T t; void check() override final { throw &t; } }; struct A { virtual ~A() {} virtual void print() = 0;}; struct B : public A { int x; B(int y) : x(y) {} void print() override final { std::cout << x; } }; int main() { Base* b = new Derived<B>(B(5)); A* p = b->IsDerivedFrom<A>(); p->print(); } Whilst this is hardly the cleanest piece of code I've ever written, it also provides a base for implementing a more generic any_cast<ValueType>, which could succeed if ValueType is a base class of the stored type. Amazingly, the Standard requires the code to work but does not provide a cleaner means of implementation. I also note that, for some configurations, you could fall back to the Itanium ABI provided function directly, which would presumably be substantially faster and cleaner. Enabling this variety of any_cast would substantially improve the composability of boost::any. For example, it's arguable that std::function is merely boost::any but with additional interface requirements. With such an any_cast enhancement, it would be quite trivial to compose std::function implementations or similar concepts on top of boost::any.

2013/11/26 DeadMG <wolfeinstein@gmail.com>
Hello,
I've been looking at ABIs and such (various unpleasant reasons). But I recently created the following code:
#include <iostream>
struct Base { virtual void check() = 0; template<typename T> T* IsDerivedFrom() { try { check(); } catch(T* p) { return p; } catch(...) { return nullptr; } return nullptr; } };
template<typename T> struct Derived : public Base { Derived(T obj) : t(obj) {} T t; void check() override final { throw &t; } };
struct A { virtual ~A() {} virtual void print() = 0;}; struct B : public A { int x; B(int y) : x(y) {} void print() override final { std::cout << x; } };
int main() { Base* b = new Derived<B>(B(5)); A* p = b->IsDerivedFrom<A>(); p->print(); }
Whilst this is hardly the cleanest piece of code I've ever written, it also provides a base for implementing a more generic any_cast<ValueType>, which could succeed if ValueType is a base class of the stored type. Amazingly, the Standard requires the code to work but does not provide a cleaner means of implementation.
This is a very interesting approach. But it has two drawbacks, because of exceptions usage: * it is slow * it won't work with exceptions disabled This can be implemented as a separate `polymorphic_any_cast` cast that is available only with exceptions on. In that way it won't affect performance of the existing any_casts and will improve usability. I'm not *the official* maintainer of the Boost.Any library, I'm just the one who made all the latest changes with rvalues and C++11 support. But if there'll be no objections and the official maintainer won't appear I can add this functionality to Boost.Any. -- Best regards, Antony Polukhin

I'd agree with implementing it separately, at least for now. Hopefully in the future, the Standard will provide facilities for it. It shouldn't be too difficult to put through Committee since it's already been demonstrated that the feature must be implemented by all implementations today, even if the existing characteristics of accessing it are very unfriendly. But what I will note is that for some implementations, you can do a lot better than this. For example, on Clang, you can use __has_include toconditionally fall back to the Itanium ABI function directly.<https://svn.boost.org/trac/boost/ticket/6773> This wouldn't require exceptions and would reduce the cost from throw/catch to dynamic_cast, which is quite a bit more reasonable. In any case, I merely wanted to make the maintainers of Boost.Any aware that there is a generic implementation of such a polymorphic_any_cast, even if it's not ideal. Then you can specialize for different implementations and such. On 27 November 2013 08:25, Antony Polukhin <antoshkka@gmail.com> wrote:
2013/11/26 DeadMG <wolfeinstein@gmail.com>
Hello,
I've been looking at ABIs and such (various unpleasant reasons). But I recently created the following code:
#include <iostream>
struct Base { virtual void check() = 0; template<typename T> T* IsDerivedFrom() { try { check(); } catch(T* p) { return p; } catch(...) { return nullptr; } return nullptr; } };
template<typename T> struct Derived : public Base { Derived(T obj) : t(obj) {} T t; void check() override final { throw &t; } };
struct A { virtual ~A() {} virtual void print() = 0;}; struct B : public A { int x; B(int y) : x(y) {} void print() override final { std::cout << x; } };
int main() { Base* b = new Derived<B>(B(5)); A* p = b->IsDerivedFrom<A>(); p->print(); }
Whilst this is hardly the cleanest piece of code I've ever written, it also provides a base for implementing a more generic any_cast<ValueType>, which could succeed if ValueType is a base class of the stored type. Amazingly, the Standard requires the code to work but does not provide a cleaner means of implementation.
This is a very interesting approach. But it has two drawbacks, because of exceptions usage: * it is slow * it won't work with exceptions disabled
This can be implemented as a separate `polymorphic_any_cast` cast that is available only with exceptions on. In that way it won't affect performance of the existing any_casts and will improve usability.
I'm not *the official* maintainer of the Boost.Any library, I'm just the one who made all the latest changes with rvalues and C++11 support. But if there'll be no objections and the official maintainer won't appear I can add this functionality to Boost.Any.
-- Best regards, Antony Polukhin
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Antony Polukhin wrote:
I'm not *the official* maintainer of the Boost.Any library, I'm just the one who made all the latest changes with rvalues and C++11 support. But if there'll be no objections and the official maintainer won't appear I can add this functionality to Boost.Any.
If I'm still the official maintainer I can happily pass my maintainership to Antony. PS do you know how type_erasure::any_cast handles this case? Alex

AMDG On 11/27/2013 12:52 PM, Alexander Nasonov wrote:
Antony Polukhin wrote:
I'm not *the official* maintainer of the Boost.Any library, I'm just the one who made all the latest changes with rvalues and C++11 support. But if there'll be no objections and the official maintainer won't appear I can add this functionality to Boost.Any.
If I'm still the official maintainer I can happily pass my maintainership to Antony.
PS do you know how type_erasure::any_cast handles this case?
It behaves exactly like boost::any_cast. In Christ, Steven Watanabe

2013/11/28 Alexander Nasonov <alnsn@yandex.ru>
Antony Polukhin wrote:
I'm not *the official* maintainer of the Boost.Any library, I'm just the one who made all the latest changes with rvalues and C++11 support. But if there'll be no objections and the official maintainer won't appear I can add this functionality to Boost.Any.
If I'm still the official maintainer I can happily pass my maintainership to Antony.
Thanks! I'll do my best. -- Best regards, Antony Polukhin

At the moment, it's not possible to compose std::function on top of boost::any because you can't get the interface back out of boost::any. But with a polymorphic_any_cast, you can. Consider the following: template<typename Signature> class function; template<typename Ret, typename... Args> class function<Ret(Args...)> { boost::any contents; struct callable { virtual Ret call(Args... args) = 0; }; template<typename F> struct derived : callable { F f; derived(F obj) : f(std::move(obj)) {} derived(derived&&) = default; derived(const derived&) = default; derived& operator=(derived&&) = default; derived& operator=(const derived&) = default; Ret call(Args... args) { return f(std::forward<Args>(args)...); } }; public: template<typename F> function(F f, /* constraint */ = 0) : contents(derived<F>(std::move(f))) {} function(const function&) = default; function(function&&) = default; function& operator=(const function&) = default; function& operator=(function&&) = default; explicit operator bool() const { return contents; } Ret operator()(Args... args) { if (auto callable = boost::polymorphic_any_cast<callable*>(&contents)) return callable->call(std::forward<Args>(args)...); throw std::bad_function_call(); } }; Here, pretty much all of, well, everything, is just delegated to boost::any. This isn't the entire interface, but enough that you should be able to get the idea. Even on an Itanium ABI system where boost::polymorphic_any_cast can become a dynamic_cast or you assume future Standard support, this won't be as efficient as a specialized std::function implementation, or one based on the more appropriate value_ptr<T>. But the interface offered by polymorphic_any_cast is substantially more flexible than is required here. On 28 November 2013 13:36, Antony Polukhin <antoshkka@gmail.com> wrote:
2013/11/28 Alexander Nasonov <alnsn@yandex.ru>
I'm not *the official* maintainer of the Boost.Any library, I'm just
Antony Polukhin wrote: the
one who made all the latest changes with rvalues and C++11 support. But if there'll be no objections and the official maintainer won't appear I can add this functionality to Boost.Any.
If I'm still the official maintainer I can happily pass my maintainership to Antony.
Thanks! I'll do my best.
-- Best regards, Antony Polukhin
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 26 November 2013 09:24, DeadMG <wolfeinstein@gmail.com> wrote:
Enabling this variety of any_cast would substantially improve the composability of boost::any. For example, it's arguable that std::function is merely boost::any but with additional interface requirements.
Well, they both use type erasure. I don't see how this exception trick helps, though.
With such an any_cast enhancement, it would be quite trivial to compose std::function implementations or similar concepts on top of boost::any.
Do you have a prototype implementation somewhere that we can look at? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
participants (5)
-
Alexander Nasonov
-
Antony Polukhin
-
DeadMG
-
Nevin Liber
-
Steven Watanabe