Boost logo

Boost :

Subject: Re: [boost] Interest in a container which can hold multiple data types?
From: Boris Rasin (boris_at_[hidden])
Date: 2015-05-12 10:19:54


On 5/11/2015 10:25 AM, Rob Stewart wrote:
> On May 10, 2015 4:30:05 PM EDT, James Armstrong <armstrhu_at_[hidden]> wrote:
>> On Sun, May 10, 2015 at 12:11 PM, Rob Stewart
>> <rob.stewart_at_[hidden]>
>> wrote:
>>
>>> Create customization points. Implement the default access method and
>>> permit customization for other types. You could provide some common
>>> specializations in separate headers so users don't always have to
>> reinvent
>>> the same wheel.
>> So I worked on this a little bit. What I did was make a function
>> pointer
>> to allow the user to define their own access function. They could
>> write
>> something along the lines of
>>
>> template<typename T>
>> void* get_boost_any(boost::any* data)
>> {
>> return (void*)boost::any_cast<T>(data);
>> }
>>
>> template<typename U, typename T1, typename T2, ... typename TN>
>> void* get_boost_variant(boost::variant<T1,T2,...,TN>* data)
>> {
>> return (void*)boost::get<U>(data);
>> }
>>
>> The problem with this is there is a separate function for each T
>> created so
>> a single function pointer doesn't quite work.
> Those aren't function pointers. They are function templates. You're on the right track, but you're not using overloading to your advantage. You need a get function template that is overloaded for the various holder types.
>
> namespace custom
> {
> template<class T>
> T &
> get(boost::any & _value)
> {
> return boost:: any_cast<T>(_value);
> }
> }
>
> You then write code like the following for your access:
>
> custom::get<T>(value);
>
> Regardless of the value type, be it any, variant, or what have you, with an appropriate overload of get(), you'd be able to extract the value. IOW, your code determines the interface(s) needed for common interactions with the holder types, and then it relies on specializations and/or overloads to adapt to the holder types.
>
> If one wants to use a new type with your container, one must specialize or overload the customization points you've chosen.
>
> It is possible to capture all customization points into a single policy class, but that can be less flexible in some cases. I'm not saying it isn't appropriate for your case. I'm just saying it isn't the right thing by default.
>
> In the example above, I've exposed the calling code to an exception should the any_cast fail. You have to decide whether that's acceptable and, if not, require your own exception type or have get return T*.

There is already well established customization point for this:

#include <utility>

try {
   using std::get;
   auto val = get<T>(value);
catch(...) {
   // handle exception
}

This already works for std::tuple, std::pair and boost::variant. One
could also add implementation for boost::any:

#include <boost/any.hpp>

namespace boost {
template<typename T>
inline T get(const any& a)
{
   return any_cast<T>(a);
}
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk