Is there an elegant way to initialize an instance of boost::any with a C-style string constant?

Hello,
I would like to ask you about the best solution to initialize a
boost::any instance with a C-string constant. Both the most legible
(IMHO) possibilities fail:
boost::any foo("foo");
boost::any bar;
bar = "bar";
Compiler (MSVC 2008 in my case) complains about them:
...\boost\any.hpp(117) : error C2536:
'boost::any::holder<ValueType>::boost::any::holder<ValueType>::held'
: cannot specify explicit initializer for arrays
with [ ValueType=const char [4] ]
...\boost\any.hpp(134) : see declaration of
'boost::any::holder<ValueType>::held'
with [ ValueType=const char [4] ]
...\boost\any.hpp(115) : while compiling class template
member function
'boost::any::holder<ValueType>::holder(ValueType (&))'
with [ ValueType=const char [4] ]
...\boost\any.hpp(41) : see reference to class template instantiation
'boost::any::holder<ValueType>' being compiled
with [ ValueType=const char [4] ]
...\test.cpp(10) : see reference to function template instantiation
'boost::any::any

to get this to compile write:
boost::any foo((const char*)"foo");
I suggested some time ago to add a special constructor:
template

Well, a little shorter as the static_cast version but still a "superfluous"
cast.
I could not find anything about it but the thread which I referred in the
first post to. Do you remember why the constructor has not been added to the
official version?
Ferda
to get this to compile write:
boost::any foo((const char*)"foo");
I suggested some time ago to add a special constructor:
template
any(T _ap[SIZE]); which should do the same like any(T *_p);
Peter
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Ferdinand Prantl Sent: Monday, June 30, 2008 08:57 To: boost-users@lists.boost.org Subject: [Boost-users] Is there an elegant way to initialize an instance ofboost::any with a C-style string constant?
Hello,
I would like to ask you about the best solution to initialize a boost::any instance with a C-string constant. Both the most legible (IMHO) possibilities fail:
boost::any foo("foo");
boost::any bar; bar = "bar";
Compiler (MSVC 2008 in my case) complains about them:
...\boost\any.hpp(117) : error C2536: 'boost::any::holder<ValueType>::boost::any::holder<ValueType>::held' : cannot specify explicit initializer for arrays with [ ValueType=const char [4] ] ...\boost\any.hpp(134) : see declaration of 'boost::any::holder<ValueType>::held' with [ ValueType=const char [4] ] ...\boost\any.hpp(115) : while compiling class template member function 'boost::any::holder<ValueType>::holder(ValueType (&))' with [ ValueType=const char [4] ] ...\boost\any.hpp(41) : see reference to class template instantiation 'boost::any::holder<ValueType>' being compiled with [ ValueType=const char [4] ] ...\test.cpp(10) : see reference to function template instantiation 'boost::any::any
(ValueType (&))' being compiled with [ ValueType=const char [4] ] Obviously the string constant is considered of the type chat[4] which lacks CopyConstructible and Assignable requirements. Wrapping the constant in some expression which satisfies the requiremenst spoils the beauty of a simple code or brings unnecessary (for the constant handling) object:
boost::any foo(static_cast
("foo")); boost::any foo(std::string("foo")); Such solutions were suggested in the thread http://lists.boost.org/Archives/boost/2003/01/43460.php but I was hoping there could be something better. I suppose there is no way to persuade the compiler to consider the constant to be const char *...
Why has not been the following constructor added to boost::any? The array would make it there passing just one conversion:
template<typename ValueType> any(const ValueType * value) : content(new holder
(value)) {} Someone could say that that it is more error prone because it enables storing a pointer which can be invalid as soon as the boost::any instance leaves the scope but the error can be made anyway:
boost::any foo(std::string("foo").c_str());
Another possibility would be to match the array type exactly but it has probably no benefit:
template<typename ValueType> any(const ValueType value []) : content(new holder
(value)) {} Do you see any problems with such constructors? How do you use string constants with boost::any?
Thank you, Ferda Prantl
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Peter Foelsche wrote:
I suggested some time ago to add a special constructor:
template
any(T _ap[SIZE]); which should do the same like any(T *_p);
Ferdinand Prantl wrote:
Well, a little shorter as the static_cast version but still a "superfluous" cast.
I could not find anything about it but the thread which I referred in the first post to. Do you remember why the constructor has not been added to the official version?
I don't know, but it makes sense to me: an array is not just a pointer!
boost::any always stores a /copy/ of its constructor argument or
assignment argument. So /if/ it would support built-in arrays, I think
it should copy their elements internally. Still, it appears technically
possible to add array support to boost::any, e.g., by having it
internally hold a wrapper<ValueType>, instead of a ValueType object (as
holder<ValueType>::held data member):
template<typename ValueType>
struct wrapper
{
ValueType data;
explicit wrapper(const ValueType & value)
: data(value)
{
}
};
The wrapper would need to be specialized for array types, copying the
array elements during construction:
template

On Mon, Jun 30, 2008 at 8:46 PM, Niels Dekker - mail address until
2008-12-31
Peter Foelsche wrote:
I suggested some time ago to add a special constructor:
template
any(T _ap[SIZE]); which should do the same like any(T *_p);
Ferdinand Prantl wrote:
Well, a little shorter as the static_cast version but still a "superfluous" cast.
I don't know, but it makes sense to me: an array is not just a pointer! boost::any always stores a /copy/ of its constructor argument or assignment argument. So /if/ it would support built-in arrays, I think it should copy their elements internally. Still, it appears technically possible to add array support to boost::any, e.g., by having it internally hold a wrapper<ValueType>, instead of a ValueType object (as holder<ValueType>::held data member): [snip] The wrapper would need to be specialized for array types, copying the array elements during construction:
Hi guys, Thanks for your suggestions! Niels, you nailed it! An array can be used as a pointer but should not be stored as pointer (generally, at least). The current requirements of boost::any ensure that the contained object is always valid there (if not used too wildly). I should have thought about the copying myself... :-) Your wrapper is an elegant solution isolating the construction differences from the rest of the holder template. At first I thought about specializing the holder template itself but I tend to like you proposal more. I knocked up the implementation and it seems working well. I will try to get it to boost. Thanks again, Ferda

I don't know, but it makes sense to me: an array is not just a pointer! boost::any always stores a /copy/ of its constructor argument or assignment argument. So /if/ it would support built-in arrays, I think it should copy their elements internally.
A C++ programmer expects that a pointer is being passed everywhere where he is passing an array argument.

On Wed, Jul 9, 2008 at 7:25 PM,
I don't know, but it makes sense to me: an array is not just a pointer! boost::any always stores a /copy/ of its constructor argument or assignment argument. So /if/ it would support built-in arrays, I think it should copy their elements internally.
A C++ programmer expects that a pointer is being passed everywhere where he is passing an array argument.
Yes it is. But the type is different and can be accepted and handled differently if it makes sense. Ferda

Ferdinand Prantl wrote:
Thanks for your suggestions! Niels, you nailed it! [...] The current requirements of boost::any ensure that the contained object is always valid there (if not used too wildly). I should have thought about the copying myself... :-) Your wrapper is an elegant solution isolating the construction differences from the rest of the holder template.
I'm glad you like it. :-) But how do you use it in practice? The added boost::any array support I suggested would require you to always specify the number of character, when retrieving C-style string (char[N]) from a boost::any. Wouldn't it? Maybe an extra function, boost::any::size_of_value(), would be helpful, returning the number of bytes of the stored object. What do you think? How would you deal with various string lengths, within your application? BTW, after re-reading, I found two shortcomings to the implementation as I originally suggested, caused by the implementation of the wrapper: explicit wrapper(const ElementType (& value)[NumberOfElements]) { std::copy(value, value + NumberOfElements, data); } First of all, it doesn't support storing a multidimentional array (e.g. int[42][69]) into a boost::any. Secondly, it copies its argument by means of copy-assignment, instead of copy-initialization. So when T is a class, wrapping an array of T would do default-construction + assignment, instead of just copy-construction. I'm pretty sure that both of these issues can be solved, though. The data would need to be stored in a boost::aligned_storage, and the copying should probably be done by placement-new, to solve the second issue. Anyway, these two issues are irrelevant to your request for C-style string support... Good luck, Niels

On Wed, Jul 9, 2008 at 7:46 PM, Niels Dekker
boost::any array support I suggested would require you to always specify the number of character, when retrieving C-style string (char[N]) from a boost::any. Wouldn't it?
Damn' you're right again. It broke my code. I realized that I edited the final version in a different file than I included, oh my... I use boost::any for serialization and deserialization of both user-provided values and hard-coded constants. Stream output has to be done a little clumsily by a custom operator<<() which consists of a big if/elseif code block deciding what to do according to boost::any::type(). I found boost::any a little easier to use than boost::variant for recursive structures. I Well, it throws me back. Exposing the number of elements of arrays by boost::any::size_of_value() would help the safety a little but I would still have to use unsafe_any_cast<ElemType>() assigning it to a ElemType const *... And I would not be able to decide about the type by typeid(); at least without introducing any other helper methods. Bad.
First of all, it doesn't support storing a multidimentional array (e.g. int[42][69]) into a boost::any.
Hmm, even if I will not need it, it would be probably unacceptable for a general library.
Secondly, it copies its argument by means of copy-assignment, instead of copy-initialization. So when T is a class, wrapping an array of T would do default-construction + assignment, instead of just copy-construction.
Yes, it adds another requirement on ValueType which the current boost::any does not need. Its assignment operator uses std::swap() which could be used to lessen this but still, generally it remains. It looks like that retaining the array type would cause quite a trouble in getting the data out of the boost::any object. Not speaking about storing it appropriately. It seems that just storing a pointer does not bring too much overhead. I will have to rethink it. Thank you very much for your deep insight! Ferda

Ferdinand Prantl wrote:
I use boost::any for serialization and deserialization of both user-provided values and hard-coded constants. Stream output has to be done a little clumsily by a custom operator<<() which consists of a big if/elseif code block deciding what to do according to boost::any::type().
Would it be helpful to you if boost::any would have a function to
retrieve its value "as a string"? I /think/ such a function,
any::str(), could be implemented quite easily, as a pure virtual
function of any::placeholder, implemented within any::holder<ValueType>
as follows:
virtual const std::string str() const
{
using any_implementation_details::operator<<;
std::ostringstream stream;
stream << held;
return stream.str();
}
The namespace any_implementation_details would have an empty default
implementation of operator<<:
namespace any_implementation_details
{
template
Thank you very much for your deep insight!
You're welcome :-) Kind regards, Niels PS, For those who missed it, there's another thread on this iussue at the Boost developers' mailing list, "[boost] An elegant way to initialize an instance of boost::anywith a C-style string constant", http://thread.gmane.org/gmane.comp.lib.boost.devel/177324
participants (3)
-
Ferdinand Prantl
-
Niels Dekker - mail address until 2008-12-31
-
peter_foelsche@agilent.com