[[value_initialized] when T is const
I like the idea of using value_initialized for a variable to initialize a value to its value intialized value when no initial value is given. But if an initial value is given it does not work if the T is a const type. Was this intended ? Essentially if a variable is a non-const object, one can say, for example: boost::value_initialized<int> data; // data initialized to its value initialized value boost::value_initialized<int> data; boost::get(data) = arg; // data is initialized to value arg For a const value we have: boost::value_initialized<int const> data; // data initialized to its value initialized value but we can not do: boost::value_initialized<int> data; boost::get(data) = arg; // ERROR // try to initialize data to value arg So there is no way to initialize a const T to a value when using boost::value_initialized<T>. This presents a problem in a template class where T can be a const type: template <class T> struct SomeTemplate<T> { boost::value_initialized<T> data; SomeTemplate() { } // always good SomeTemplate(T arg) { boost::get(data) = arg; // FAILS with a const T, // such as if SomeTemplate<int const> is instantiated with any int value // as in 'SomeTemplate<int const> st(4);' } }; In this case boost::value_initialized can not be used. This makes it much less usable in my estimation since the creator of a template class wanting to use boost::value_initialized can only do so if he restricts that template type to a non-const value. If he does not make that restriction then he must go back to initialization by hand and forgo the advantages of value_initialized entirely. It would seem that this limitation could be lifted if the boost::value_initialized template had a constructor which enabled one to initialize the value in cases where initialization to a value initialized state was not desired. Then, despite T being a const type, one could initialize the variable to a specific value.
This is a correction to my OP. I give it again in full. I like the idea of using value_initialized for a variable to initialize a value to its value intialized value when no initial value is given. But if an initial value is subsequently given it does not work if the T is a const type. Was this intended ? Essentially if a variable is a non-const object, one can say, for example: boost::value_initialized<int> data; // data initialized to its value initialized value boost::get(data) = arg; // data is initialized to value arg For a const value we have: boost::value_initialized<int const> data; // data initialized to its value initialized value but we can not do: boost::get(data) = arg; // ERROR // trying to initialize data to value arg fails So there is no way to initialize a const T to a value when using boost::value_initialized<T>. Essentially for a const type, boost::value_initialized initializes the object to its value initialized value and subsequently it can never be changed. It can be argued that if one is specifying a const type and one wants to initialize the object of that type to a non-value initialized value, simply do not use boost::value_initialized. But consider the problem in a template class where T might be a non-const or a const type depending on how the user instantiates the template class: template <class T> struct SomeTemplate<T> { boost::value_initialized<T> data; SomeTemplate() { } // always good SomeTemplate(T arg) { boost::get(data) = arg; // FAILS with a const T, // such as if SomeTemplate<int const> is instantiated with any int value // as in 'SomeTemplate<int const> st(4);' } }; In this case, where T is passed to the template instantiation as a const type, boost::value_initialized can not be used. This makes it much less usable in my estimation since the creator of a template class wanting to use boost::value_initialized can only do so if he restricts that template type to a non-const value. If he does not make that restriction then he must go back to initialization by hand and forgo the advantages of value_initialized entirely. It would seem that this limitation could be lifted if the boost::value_initialized template had a constructor which enabled one to initialize the value in cases where initialization to a value initialized state was not desired. Then, despite T being a const type, one could initialize the variable to a specific value in the constructor, while keeping the current semantics which disallow changing the value of a const type once it has been initialized.
Edward Diener wrote:
I like the idea of using value_initialized for a variable to initialize a value to its value intialized value when no initial value is given. But if an initial value is subsequently given it does not work if the T is a const type. Was this intended ?
I think so, yes. (Nit picking: a subsequently given value is not an initial value!)
It can be argued that if one is specifying a const type and one wants to initialize the object of that type to a non-value initialized value, simply do not use boost::value_initialized.
Yes, I think so too. (I'm sorry!)
It would seem that this limitation could be lifted if the boost::value_initialized template had a constructor which enabled one to initialize the value in cases where initialization to a value initialized state was not desired. Then, despite T being a const type, one could initialize the variable to a specific value in the constructor, while keeping the current semantics which disallow changing the value of a const type once it has been initialized.
Of course, technically speaking, a constructor could be added to value_initialized<T> that accepts a T argument, and copies its value. But if so, value_initialized<T> would no longer guarantee to always deliver value-initialized objects. Wouldn't that be a drawback? BTW There's still a fix of a "const issue" of value_initialized underway. Please have a look: https://svn.boost.org/trac/boost/ticket/2548 Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center
Niels Dekker - address until 2010-10-10 wrote:
Edward Diener wrote:
I like the idea of using value_initialized for a variable to initialize a value to its value intialized value when no initial value is given. But if an initial value is subsequently given it does not work if the T is a const type. Was this intended ?
I think so, yes. (Nit picking: a subsequently given value is not an initial value!)
Agreed. Phrasing it better I should have said in the second sentence: 'But if a value is subsequently set it does not...etc.'
It can be argued that if one is specifying a const type and one wants to initialize the object of that type to a non-value initialized value, simply do not use boost::value_initialized.
Yes, I think so too. (I'm sorry!)
It would seem that this limitation could be lifted if the boost::value_initialized template had a constructor which enabled one to initialize the value in cases where initialization to a value initialized state was not desired. Then, despite T being a const type, one could initialize the variable to a specific value in the constructor, while keeping the current semantics which disallow changing the value of a const type once it has been initialized.
Of course, technically speaking, a constructor could be added to value_initialized<T> that accepts a T argument, and copies its value. But if so, value_initialized<T> would no longer guarantee to always deliver value-initialized objects. Wouldn't that be a drawback?
I don't see it as a big drawback but perhaps my viewpoint is limited to what I feel I need. The documentation would simply explain that when the constructor is not used, the guarantee holds, but when the constructor is used the object is no longer value initialized but constructed passing the value to the object type's constructor. This would still allow value_initialized to have its original intended effect, while providing a little extra functionality. You could even provide the constructor only for top-level const T ( through the 'Structure Selection' technique as outlined in section 9.4 of the "C++ Template Metaprogramming Book" ), since it is not needed for non-const types whose value can be subsequently set in any of the three ways outlined in the current documentation ( I agree 'get' is best ). Of course this is a one-off situation purely to allow a top-level const value to be initialized to something other than its value_initialized state. I like one-off situations as little as the next programmer, so if there is a better general solution it should be pursued. But right now I don't see one for the problem I outlined.
BTW There's still a fix of a "const issue" of value_initialized underway. Please have a look: https://svn.boost.org/trac/boost/ticket/2548
I do not see how this fixes the situation I outlined in my original OP. That I can get the value back as const T & for a const value_initialized object and T & for a non-const value_initialized object does not help me at all. If T would still be some top-level const, I could not modify it subsequently. Would you please explain how the change made in that ticket solves the problem I have outlined ? I want to emphasize again the point of my original OP. Using value_initialized in a template class or template function where the type of the value_initialized variable is a parameterized type always fails if: 1) The parameterized type is passed as a top-level const. 2) The value_initialized variable needs to be set to anything other than its value_initialized value. I think number 2) above is a very probable situation. Perhaps the situation where a parameterized type can be passed as const or non-const is too rare and therefore it is not worth looking at value_initialized for a "solution". In that case one solution is that if the programmer of the template accepts either a const or non-const value, value_initialized should only be used if the value is guaranteed to never being changed from its value_initialized state. That is a very rare sitution to say the least. Another solution, more onerous programatically, is that the programmer use a value_initialized variable for the non-const type but a normal const variable set to an immediate value for the const type using template metaprogramming. Brrr, that really complicates the programmer's template design. I did design a template class I am coding to use value_initialized and afterward, when I was testing it, realized that when a const type gets used there is no way of setting the value_initialized value to a non-value_initialized value either during the construction of the object or subsequently. Since my template class is meant to be used by end-users, and I don't want to control the constness of the type passed as a template parameter, value_initialized can't be used by me as it currently exists.
Of course, technically speaking, a constructor could be added to value_initialized<T> that accepts a T argument, and copies its value. But if so, value_initialized<T> would no longer guarantee to always deliver value-initialized objects. Wouldn't that be a drawback?
Edward Diener wrote:
I don't see it as a big drawback but perhaps my viewpoint is limited to what I feel I need.
Maybe it's not a big drawback. It's just something we need to consider, before we can (possibly) resolve your issue. (I'm saying "we" because I also got involved with value_initialized<T>, but the utility is from Fernando Cacciola, of course!)
The documentation would simply explain that when the constructor is not used, the guarantee holds, but when the constructor is used the object is no longer value initialized but constructed passing the value to the object type's constructor.
Certainly, the new feature should be well documented.
You could even provide the constructor only for top-level const T ( through the 'Structure Selection' technique as outlined in section 9.4 of the "C++ Template Metaprogramming Book" )
I think it's preferable to have a solution that treats const T and non-const T alike.
I like one-off situations as little as the next programmer, so if there is a better general solution it should be pursued.
Right :-)
Please have a look: https://svn.boost.org/trac/boost/ticket/2548
I do not see how this fixes the situation I outlined in my original OP.
Indeed, it does not. I just mentioned it because you might be interested, as it's also about const-ness and value_initialized.
I did design a template class I am coding to use value_initialized and afterward, when I was testing it, realized that when a const type gets used there is no way of setting the value_initialized value to a non-value_initialized value either during the construction of the object or subsequently. Since my template class is meant to be used by end-users, and I don't want to control the constness of the type passed as a template parameter, value_initialized can't be used by me as it currently exists.
I think your case is clear. Do you have a proposed resolution? :-) I guess we'd need to add an extra constructor that would copy from T to value_initialized<T>, right? I'm not yet entirely sure about its signature... IMO, all of them have their pro's and cons. For example: [1] value_initialized(const T&); [2] explicit value_initialized(const T&); [3] value_initialized(const T&, explicit_copy_t); [4] explicit template <class U> value_initialized(const U&); [5] template <class U> value_initialized(const U&, explicit_copy_t); I think each of them would be good enough to fix your issue, right? Option [1] is most straight forward. It allows implicit conversion from T to value_initialized<T>, which doesn't seem unreasonable. Still people might find such implicit conversion scary, and prefer to add an explicit keyword (option [2]). But there isn't much difference between [1] and [2] in your use case, having a value_initialized<T> as data member. So instead, an extra "dummy" parameter could be added, to avoid accidental copying, and to make such copying more "explicit". Like in option [3], assuming explicit_copy_t is an empty struct, struct explicit_copy_t {}. Option [4] and [5] are more generic, allowing conversion from anything that is convertible to T. Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center
Niels Dekker - address until 2010-10-10 wrote:
snipped...
Edward Diener wrote:
I did design a template class I am coding to use value_initialized and afterward, when I was testing it, realized that when a const type gets used there is no way of setting the value_initialized value to a non-value_initialized value either during the construction of the object or subsequently. Since my template class is meant to be used by end-users, and I don't want to control the constness of the type passed as a template parameter, value_initialized can't be used by me as it currently exists.
I think your case is clear. Do you have a proposed resolution? :-)
I guess we'd need to add an extra constructor that would copy from T to value_initialized<T>, right? I'm not yet entirely sure about its signature... IMO, all of them have their pro's and cons. For example:
[1] value_initialized(const T&); [2] explicit value_initialized(const T&); [3] value_initialized(const T&, explicit_copy_t); [4] explicit template <class U> value_initialized(const U&); [5] template <class U> value_initialized(const U&, explicit_copy_t);
I think each of them would be good enough to fix your issue, right?
Option [1] is most straight forward. It allows implicit conversion from T to value_initialized<T>, which doesn't seem unreasonable. Still people might find such implicit conversion scary, and prefer to add an explicit keyword (option [2]). But there isn't much difference between [1] and [2] in your use case, having a value_initialized<T> as data member. So instead, an extra "dummy" parameter could be added, to avoid accidental copying, and to make such copying more "explicit". Like in option [3], assuming explicit_copy_t is an empty struct, struct explicit_copy_t {}. Option [4] and [5] are more generic, allowing conversion from anything that is convertible to T.
I do not really understand the need for the 'explicit_copy_t' in your possibilities. I favor 2), although 1) is fine also. I see little reason for the templated constructor in practical use, especially since the current usage of value_initialized does not consider conversions to and from the T type in any of its functionality.
I guess we'd need to add an extra constructor that would copy from T to value_initialized<T>, right? I'm not yet entirely sure about its signature... IMO, all of them have their pro's and cons. For example:
[1] value_initialized(const T&); [2] explicit value_initialized(const T&); [3] value_initialized(const T&, explicit_copy_t); [4] explicit template <class U> value_initialized(const U&); [5] template <class U> value_initialized(const U&, explicit_copy_t);
Edward Diener wrote:
I do not really understand the need for the 'explicit_copy_t' in your possibilities.
If I recall correctly, there might be some rather exotic cases where adding value_initialized(const T&) would cause ambiguity in a program that would work before. The compiler might not be able to choose between value_initialized(const T&) and value_initialized(const value_initialized&) in some rare cases. But maybe I'm wrong... If I can't find such a case before the end of the week, I'll assume that it's a non-issue :-)
I favor 2), although 1) is fine also. I see little reason for the templated constructor in practical use, especially since the current usage of value_initialized does not consider conversions to and from the T type in any of its functionality.
It /might/ be nice to allow conversion from U to value_initialized<T> whenever there is a conversion from U to T. But if nobody needs it, let's forget option [4] and [5] for the time being. It would be helpful if you create a ticket regarding your request: https://svn.boost.org/trac/boost/newticket Kind regards, Niels
Niels Dekker - address until 2010-10-10 wrote:
I guess we'd need to add an extra constructor that would copy from T to value_initialized<T>, right? I'm not yet entirely sure about its signature... IMO, all of them have their pro's and cons. For example:
[1] value_initialized(const T&); [2] explicit value_initialized(const T&); [3] value_initialized(const T&, explicit_copy_t); [4] explicit template <class U> value_initialized(const U&); [5] template <class U> value_initialized(const U&, explicit_copy_t);
Edward Diener wrote:
I do not really understand the need for the 'explicit_copy_t' in your possibilities.
If I recall correctly, there might be some rather exotic cases where adding value_initialized(const T&) would cause ambiguity in a program that would work before. The compiler might not be able to choose between value_initialized(const T&) and value_initialized(const value_initialized&) in some rare cases. But maybe I'm wrong... If I can't find such a case before the end of the week, I'll assume that it's a non-issue :-)
You can remove the copy constructor if you want by the usual means of making it private and providing no implementation. I admit I tend to do that whenever I want to forbid copy construction ( as well as assignment ). But I rarely have to code for the vagaries of many compilers as Boost implementations have to do.
I favor 2), although 1) is fine also. I see little reason for the templated constructor in practical use, especially since the current usage of value_initialized does not consider conversions to and from the T type in any of its functionality.
It /might/ be nice to allow conversion from U to value_initialized<T> whenever there is a conversion from U to T. But if nobody needs it, let's forget option [4] and [5] for the time being.
It would be helpful if you create a ticket regarding your request: https://svn.boost.org/trac/boost/newticket
I created the ticket. BTW value_initialized is not listed among the components one can choose, although it should be, so I chose "utility" instead. Hopefully it will be assigned to you or Fernando.
Niels Dekker - address until 2010-10-10 wrote:
I guess we'd need to add an extra constructor that would copy from T to value_initialized<T>, right? I'm not yet entirely sure about its signature... IMO, all of them have their pro's and cons. For example:
[1] value_initialized(const T&); [2] explicit value_initialized(const T&); [3] value_initialized(const T&, explicit_copy_t); [4] explicit template <class U> value_initialized(const U&); [5] template <class U> value_initialized(const U&, explicit_copy_t);
Edward Diener wrote:
I do not really understand the need for the 'explicit_copy_t' in your possibilities.
If I recall correctly, there might be some rather exotic cases where adding value_initialized(const T&) would cause ambiguity in a program that would work before. The compiler might not be able to choose between value_initialized(const T&) and value_initialized(const value_initialized&) in some rare cases. But maybe I'm wrong... If I can't find such a case before the end of the week, I'll assume that it's a non-issue :-)
I favor 2), although 1) is fine also. I see little reason for the templated constructor in practical use, especially since the current usage of value_initialized does not consider conversions to and from the T type in any of its functionality.
It /might/ be nice to allow conversion from U to value_initialized<T> whenever there is a conversion from U to T. But if nobody needs it, let's forget option [4] and [5] for the time being.
It would be helpful if you create a ticket regarding your request: https://svn.boost.org/trac/boost/newticket
As a quick 'heads up', if you add a constructor to value_initialized<T>, make sure you also remember to add the default constructor.
Edward Diener wrote:
As a quick 'heads up', if you add a constructor to value_initialized<T>, make sure you also remember to add the default constructor.
Did you already take a look? value_initialized<T> has always had a
user-defined default constructor.
Please check
Niels Dekker - address until 2010-10-10 wrote:
Edward Diener wrote:
As a quick 'heads up', if you add a constructor to value_initialized<T>, make sure you also remember to add the default constructor.
Did you already take a look? value_initialized<T> has always had a user-defined default constructor.
My very stupid error in not realizing that value_initialized<T> had to have a user-defined default constructor.
Please check
It would be helpful if you could already implement the new feature in your local copy of "value_init.hpp", to see if it works. If so, you could add your implementation as a proposed resolution to the ticket, https://svn.boost.org/trac/boost/ticket/3472
I will code it up locally, test it out, and then add it to the ticket.
Edward Diener wrote:
Niels Dekker - address until 2010-10-10 wrote:
Edward Diener wrote:
As a quick 'heads up', if you add a constructor to value_initialized<T>, make sure you also remember to add the default constructor.
Did you already take a look? value_initialized<T> has always had a user-defined default constructor.
My very stupid error in not realizing that value_initialized<T> had to have a user-defined default constructor.
Please check
It would be helpful if you could already implement the new feature in your local copy of "value_init.hpp", to see if it works. If so, you could add your implementation as a proposed resolution to the ticket, https://svn.boost.org/trac/boost/ticket/3472
I will code it up locally, test it out, and then add it to the ticket.
I added an attachment to the ticket which is an SVN patch file against the latest version from the SVN repository. It works for me but I have only tested it for my particular work on VC9 and VS2008.
participants (2)
-
Edward Diener
-
Niels Dekker - address until 2010-10-10