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

Hello, I would like to improve usage of boost::any with text (char*) constants. This would be the goal: boost::any foo("foo"); boost::any bar; bar = "bar"; Currently the compiler (MSVC 2008 in my case) complains about it: ...\boost\any.hpp(117) : error C2536: 'boost::any::holder< ValueType>::boost::any::holder<ValueType>::held' : cannot specify explicit initializer for arrays There are more ways to make it compiled, all of them either with an extra cast or object construction: boost::any foo(static_cast<const char *>("foo")); boost::any foo((const char *) "foo"); boost::any foo(std::string("foo")); Supposing there is no way to persuade the compiler to consider the constant not to be an array but just a pointer I would suggest adding support for arrays to boost::any. I am sorry if it has been discussed already. I found just one thread without a conclusion (http://lists.boost.org/Archives/boost/2003/01/43460.php). I asked about it in boost.users and got a nice proposal from Niels Dekker (http://thread.gmane.org/gmane.comp.lib.boost.user/37189/focus=37414). I replaced the member "held" in holder<> by a wrapper specialized for arrays: template<typename ValueType> struct wrapper { ValueType data; explicit wrapper(const ValueType & value) : data(value) {} }; template<typename ElementType, std::size_t NumberOfElements> struct wrapper<ElementType[NumberOfElements]> { typename remove_const<ElementType>::type data[NumberOfElements]; explicit wrapper(const ElementType (& value)[NumberOfElements]) { std::copy(value, value + NumberOfElements, data); } }; A new constructor in boost::any makes use of it: template<typename ElementType, std::size_t NumberOfElements> any(const ElementType (& value)[NumberOfElements]) : content(new holder<ElementType[NumberOfElements]>(value)) {} This solution is more complicated but it makes the instance of boost::any own the copy of array just like its for scalar objects. Alternatively, instead of wrapping a copy of the array, I could store just a pointer to it without any other changes in bost::any (I want to use just constants in my example): template<typename ElementType, std::size_t NumberOfElements> any(const ElementType (& value)[NumberOfElements]) : content(new holder<const ElementType*>(value)) {} I am attaching a patch to any.hpp from boost 1.35.0. I could provide a test for it too. What do you think about it? Shall I create a feature request for it? Thank you, Ferda

Ferdinand Prantl wrote:
Hello,
I would like to improve usage of boost::any with text (char*) constants. This would be the goal:
boost::any foo("foo");
This is not a char*. There is no problem putting a char* in a boost::any. It's a const char[N]. An array. To insert an object into a boost::any, the object needs to be copyable. Arrays aren't. The end.

On Jul 9, 2008, at 3:57 PM, Mathias Gaunard wrote:
Ferdinand Prantl wrote:
Hello,
I would like to improve usage of boost::any with text (char*) constants. This would be the goal:
boost::any foo("foo");
This is not a char*. There is no problem putting a char* in a boost::any. It's a const char[N]. An array. To insert an object into a boost::any, the object needs to be copyable. Arrays aren't. The end.
Arrays are badly-copyable because the C++ committee has never fixed them from their half-done status (unlike struct). Maybe we should take the lead and make a special case for allowing array objects in an boost::any. (Note for the string case, we have to include the terminating NUL, so the rules won't be irregular with non-character types, and for non-string arrays that just happen to have a character type for elements [i.e. due to template code].) -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

On Wed, Jul 9, 2008 at 10:16 PM, Daryle Walker wrote:
Arrays are badly-copyable because the C++ committee has never fixed them from their half-done status (unlike struct). Maybe we should take the lead and make a special case for allowing array objects in an boost::any. (Note for the string case, we have to include the terminating NUL, so the rules won't be irregular with non-character types, and for non-string arrays that just happen to have a character type for elements [i.e. due to template code].)
The question would be - do we want boost::any to be implicitely constructible and assignable from constant arrays? (I say I do, indeed, but... :-) If yes, another question would be how to store arrays. They are passed as pointers to functions. The easiest option would be to "downgrade" them the same way and store them as pointer to their first element. Then a boost::any object would not contain a copy of the array but a copy of the pointer. Storing the array as a full copy with its exact type brings more questions like handling multidimensional arrays, avoiding assignments when copying the array and how to get the array from the boost::any object by boost::any_cast. Ferda

Daryle Walker wrote:
Arrays are badly-copyable because the C++ committee has never fixed them from their half-done status (unlike struct).
FWIW, it's quite easy to write a template function that can copy both built-in arrays (of any number of dimensions) and Assignable types: template <typename T> void copy(const T &source, T &dest) { dest = source; } template <typename T, std::size_t N> void copy(const T (&source)[N], T (&dest)[N]) { for (std::size_t i = 0; i < N; ++i) copy(source[i], dest[i]); } So arrays aren't /that/ uncopyable :-)
Maybe we should take the lead and make a special case for allowing array objects in an boost::any.
I certainly wouldn't mind having array support for boost::any... Ferdinand Prantl wrote:
I were not arguing the type of the expression. The thing was - is it possible to modify boost::any in some way to make it usable with C-string style constants without a cast?
Is it really so bad to have a cast? What about the following syntax? boost::any foo( cast_array_to_ptr("foo") ); Having cast_array_to_ptr as follows: template<typename T, std::size_t N> T * cast_array_to_ptr(T (&arg)[N]) { return arg; }
By the way, there is a problem with the proposal made in my previous e-mail. It would be virtually impossible to get the value from the object by a cast if the array was stored with its exact type.
It wouldn't be completely impossible, though. You can have a function that returns a char-pointer, implemented by trying to cast a boost::any to char[N], for N = 1 to some reasonably high maximum constant...
Storing the array as a full copy with its exact type brings more questions like handling multidimensional arrays, avoiding assignments when copying the array and how to get the array from the boost::any object by boost::any_cast.
I'm pretty sure we can solve those questions on handling multidimensional arrays, and avoiding assignments, as I mentioned at Boost Users http://article.gmane.org/gmane.comp.lib.boost.user/37430 Anyway, just my 2 cents for today, Kind regards, -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center

On Wed, Jul 9, 2008 at 9:57 PM, Mathias Gaunard wrote:
Ferdinand Prantl wrote:
I would like to improve usage of boost::any with text (char*) constants. This would be the goal:
boost::any foo("foo");
This is not a char*. There is no problem putting a char* in a boost::any. It's a const char[N]. An array. To insert an object into a boost::any, the object needs to be copyable. Arrays aren't. The end.
I were not arguing the type of the expression. The thing was - is it possible to modify boost::any in some way to make it usable with C-string style constants without a cast? By the way, there is a problem with the proposal made in my previous e-mail. It would be virtually impossible to get the value from the object by a cast if the array was stored with its exact type. It is much easier to store it as a pointer. The only working option that remains me would be to accept pointers passed to constructor and to assignment operator as an array either/or: template<typename ValueType> any(const ValueType * value) : content(new holder<const ValueType *>(value)) { } template<typename ElementType, std::size_t NumberOfElements> any(const ElementType (& value)[NumberOfElements]) : content(new holder<const ElementType *>(value)) { } Yes, it would mean that boost::any does not accept only copyable objects, it would enable arays too and it would handle them as a const pointer to their first element. Would it be bad? Thanks, Ferda
participants (4)
-
Daryle Walker
-
Ferdinand Prantl
-
Mathias Gaunard
-
Niels Dekker - mail address until 2008-12-31