Updated boost::base_from_member for C++2011

This is in changeset 76982. I tried it on my system, with Apple-supplied GCC 4.0.1 and GCC-direct 4.6 (from MacPorts) on a Mac/PowerPC system. It just does the slam-dunk implementation of this concept that C++2011 allows (and therefore showing its power). The new code should be isolated to only systems that can handle it. Now the code is over the wall, and it's time to see who crashes & burns (hopefully no one) in the tests.... Daryle W.

Le 11/02/12 20:50, Daryle Walker a écrit :
This is in changeset 76982. I tried it on my system, with Apple-supplied GCC 4.0.1 and GCC-direct 4.6 (from MacPorts) on a Mac/PowerPC system. It just does the slam-dunk implementation of this concept that C++2011 allows (and therefore showing its power). The new code should be isolated to only systems that can handle it. Now the code is over the wall, and it's time to see who crashes& burns (hopefully no one) in the tests....
Hi, there are some problems with clang-3.0 c++0x clang-darwin.compile.c++ ../../../bin.v2/libs/test/build/clang-darwin-3.0x/debug/link-static/threading-multi/unit_test_parameters.o In file included from ../../../libs/test/src/unit_test_parameters.cpp:16: In file included from ../../../boost/test/impl/unit_test_parameters.ipp:32: In file included from ../../../boost/test/utils/runtime/cla/dual_name_parameter.hpp:21: In file included from ../../../boost/test/utils/runtime/cla/named_parameter.hpp:21: In file included from ../../../boost/test/utils/runtime/cla/basic_parameter.hpp:27: ../../../boost/utility/base_from_member.hpp:75:66: error: no matching constructor for initialization of 'boost::runtime::cla::string_name_policy' BOOST_NOEXCEPT_IF( BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType( ^ ../../../boost/config/suffix.hpp:648:53: note: expanded from: # define BOOST_NOEXCEPT_EXPR(Expression) noexcept((Expression)) ^ ../../../boost/config/suffix.hpp:647:50: note: expanded from: # define BOOST_NOEXCEPT_IF(Predicate) noexcept((Predicate)) ^ ../../../boost/utility/base_from_member.hpp:74:30: note: in instantiation of function template specialization 'boost::base_from_member<boost::runtime::cla::string_name_policy, 0>::base_from_member<const boost::base_from_member<boost::runtime::cla::string_name_policy, 0> &>' requested here explicit BOOST_CONSTEXPR base_from_member( T&& ...x ) ^ ../../../boost/test/utils/runtime/cla/named_parameter.hpp:34:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const boost::base_from_member<boost::runtime::cla::string_name_policy, 0>' to 'const boost::runtime::cla::string_name_policy' for 1st argument; class string_name_policy : public basic_naming_policy { ^ ../../../boost/test/utils/runtime/cla/named_parameter.hpp:37:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided string_name_policy(); ^ Best, Vicente

Date: Sun, 12 Feb 2012 17:15:37 +0100 From: vicente.botet@wanadoo.fr
there are some problems with clang-3.0 c++0x
clang-darwin.compile.c++ ../../../bin.v2/libs/test/build/clang-darwin-3.0x/debug/link-static/threading-multi/unit_test_parameters.o In file included from ../../../libs/test/src/unit_test_parameters.cpp:16: In file included from ../../../boost/test/impl/unit_test_parameters.ipp:32: In file included from ../../../boost/test/utils/runtime/cla/dual_name_parameter.hpp:21: In file included from ../../../boost/test/utils/runtime/cla/named_parameter.hpp:21: In file included from ../../../boost/test/utils/runtime/cla/basic_parameter.hpp:27: ../../../boost/utility/base_from_member.hpp:75:66: error: no matching constructor for initialization of 'boost::runtime::cla::string_name_policy' BOOST_NOEXCEPT_IF( BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType( ^ ../../../boost/config/suffix.hpp:648:53: note: expanded from: # define BOOST_NOEXCEPT_EXPR(Expression) noexcept((Expression)) ^ ../../../boost/config/suffix.hpp:647:50: note: expanded from: # define BOOST_NOEXCEPT_IF(Predicate) noexcept((Predicate)) ^ ../../../boost/utility/base_from_member.hpp:74:30: note: in instantiation of function template specialization 'boost::base_from_member<boost::runtime::cla::string_name_policy, 0>::base_from_member<const boost::base_from_member<boost::runtime::cla::string_name_policy, 0> &>' requested here explicit BOOST_CONSTEXPR base_from_member( T&& ...x ) ^ ../../../boost/test/utils/runtime/cla/named_parameter.hpp:34:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const boost::base_from_member<boost::runtime::cla::string_name_policy, 0>' to 'const boost::runtime::cla::string_name_policy' for 1st argument; class string_name_policy : public basic_naming_policy { ^ ../../../boost/test/utils/runtime/cla/named_parameter.hpp:37:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided string_name_policy(); ^
Any ideas for a fix? Does there need to be explicitly declared copy (and move) constructors? Daryle W.

From: darylew@hotmail.com Date: Tue, 14 Feb 2012 11:08:10 -0500
Date: Sun, 12 Feb 2012 17:15:37 +0100 From: vicente.botet@wanadoo.fr
there are some problems with clang-3.0 c++0x
clang-darwin.compile.c++ ../../../bin.v2/libs/test/build/clang-darwin-3.0x/debug/link-static/threading-multi/unit_test_parameters.o In file included from ../../../libs/test/src/unit_test_parameters.cpp:16: In file included from ../../../boost/test/impl/unit_test_parameters.ipp:32: In file included from ../../../boost/test/utils/runtime/cla/dual_name_parameter.hpp:21: In file included from ../../../boost/test/utils/runtime/cla/named_parameter.hpp:21: In file included from ../../../boost/test/utils/runtime/cla/basic_parameter.hpp:27: ../../../boost/utility/base_from_member.hpp:75:66: error: no matching constructor for initialization of 'boost::runtime::cla::string_name_policy' BOOST_NOEXCEPT_IF( BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType( ^ ../../../boost/config/suffix.hpp:648:53: note: expanded from: # define BOOST_NOEXCEPT_EXPR(Expression) noexcept((Expression)) ^ ../../../boost/config/suffix.hpp:647:50: note: expanded from: # define BOOST_NOEXCEPT_IF(Predicate) noexcept((Predicate)) ^ ../../../boost/utility/base_from_member.hpp:74:30: note: in instantiation of function template specialization 'boost::base_from_member<boost::runtime::cla::string_name_policy, 0>::base_from_member<const boost::base_from_member<boost::runtime::cla::string_name_policy, 0> &>' requested here explicit BOOST_CONSTEXPR base_from_member( T&& ...x ) ^ ../../../boost/test/utils/runtime/cla/named_parameter.hpp:34:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const boost::base_from_member<boost::runtime::cla::string_name_policy, 0>' to 'const boost::runtime::cla::string_name_policy' for 1st argument; class string_name_policy : public basic_naming_policy { ^ ../../../boost/test/utils/runtime/cla/named_parameter.hpp:37:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided string_name_policy(); ^
Any ideas for a fix? Does there need to be explicitly declared copy (and move) constructors?
I asked about this on StackOverflow, and we've discovered a new C++ gotcha. If we have a universal constructor: struct MyType{ template <typename ...Args> MyType( Args&& ...x );}; Matches every kind of argument except two: * anything with "volatile"* a "const &&" Since we have an explicitly declared constructor, the automatically defined default constructor is cancelled. That's OK since this constructor template will serve as it. The compiler will also search for constructor profiles that can act as the copy- and move-constructor, ignoring all constructor templates, even if they could match. Since there's no explicitly declared non-template constructors, MyType gains two: * MyType( MyType const & ) = default;* MyType( MyType && ) = default; Although constructor templates are ignored when determining if the automatic copy/move-constructors are made, they are NOT ignored when overload resolution needs to be done! If you're copying from a non-const object, the universal constructor will match a "MyType &" before the copy constructor's "MyType const &" would! This is what's causing the conflict. The way around it is to add an "unused" EnableIf template parameter to the constructor template that cancels the template when Args is a single argument and the argument's type is MyType. I'll work that in. Daryle W.

[Daryle Walker]
I asked about this on StackOverflow, and we've discovered a new C++ gotcha. If we have a universal constructor: struct MyType{ template <typename ...Args> MyType( Args&& ...x );}; Matches every kind of argument except two: * anything with "volatile" * a "const &&"
This is not correct - volatiles and const rvalues can be perfectly forwarded. STL

Daryle Walker wrote:
The way around it is to add an "unused" EnableIf template parameter to the constructor template that cancels the template when Args is a single argument and the argument's type is MyType.
How about using SFINAE to `noexcept` operator as in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48468 ? template <typename... T, bool NoExcept = BOOST_NOEXCEPT_EXPR(......)> explicit BOOST_CONSTEXPR base_from_member( T&& ...x ) BOOST_NOEXCEPT_IF( NoExcept ) // no std::is_nothrow_constructible... : member( static_cast<T&&>(x)... ) // ...nor std::forward needed {} This seems a bit simpler, but of course, it might be a personal taste ;) In `bool NoExcept = BOOST_NOEXCEPT_EXPR(...…)`, we have to use `MemberType(boost::declval<T>()...)` instead of `MemberType(static_cast<T&&>(x)...)`. P.S. I requested adding `noexcept` to `boost::declval`. https://svn.boost.org/trac/boost/ticket/6570 Regards, Michel

From: me Date: Wed, 15 Feb 2012 23:19:46 -0500
From: me Date: Tue, 14 Feb 2012 11:08:10 -0500
[SNIP]
Any ideas for a fix? Does there need to be explicitly declared copy (and move) constructors?
I asked about this on StackOverflow, and we've discovered a new C++ gotcha. If we have a universal constructor: [SNIP]> Although constructor templates are ignored when determining if the automatic copy/move-constructors are made, they are NOT ignored when overload resolution needs to be done! If you're copying from a non-const object, the universal constructor will match a "MyType &" before the copy constructor's "MyType const &" would! This is what's causing the conflict. The way around it is to add an "unused" EnableIf template parameter to the constructor template that cancels the template when Args is a single argument and the argument's type is MyType. I'll work that in.
I did it in (https://svn.boost.org/trac/boost/changeset/77046), so check if it works for you now. Of course, if you or someone else here has a better construction, let me know and I'll try it instead. (It still has to work for me on GCC-4.6, though.) Daryle W.

Daryle Walker wrote:
I did it in (https://svn.boost.org/trac/boost/changeset/77046), so check if it works for you now.
Both r77046 and the version with SFINEAE to noexcept work well with clang-3.0 and gcc-4.6.
Of course, if you or someone else here has a better construction, let me know and I'll try it instead. (It still has to work for me on GCC-4.6, though.)
Can NothrowConstructible be simply determined by BOOST_NOEXCEPT_EXPR(MemberType(static_cast<T&&>(x)...)) rather than BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType(static_cast<T&&>(x)...)) ? Regards, Michel

Date: Sat, 18 Feb 2012 12:04:09 +0900 From: mimomorin@gmail.com
Daryle Walker wrote:
I did it in (https://svn.boost.org/trac/boost/changeset/77046), so check if it works for you now.
Both r77046 and the version with SFINEAE to noexcept work well with clang-3.0 and gcc-4.6.
Of course, if you or someone else here has a better construction, let me know and I'll try it instead. (It still has to work for me on GCC-4.6, though.)
Can NothrowConstructible be simply determined by BOOST_NOEXCEPT_EXPR(MemberType(static_cast<T&&>(x)...)) rather than BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType(static_cast<T&&>(x)...)) ?
That's the obvious way done by everyone at first, even me. I also saw it in the GCC LibStdC++v3 source for std::is_nothrow_default_constructible. However, every operation required for a noexcept expression is considered, including any destructor calls for temporary objects. That's why there's a "declval," after all. We need to call a constructor without a corresponding destructor, and the placement-new syntax (in a no-throw version) does that. The variant used is one of the few that's illegal to override. Daryle W.

Thanks for the explanation, Daryle. Daryle Walker wrote:
However, every operation required for a noexcept expression is considered, including any destructor calls for temporary objects. That's why there's a "declval," after all. We need to call a constructor without a corresponding destructor, and the placement-new syntax (in a no-throw version) does that. The variant used is one of the few that's illegal to override.
In `MemberType(static_cast<T&&>(x)…)`, I don't see any any destruction of temporaries, since there are no temporaries involved in `static_cast<T&&>(x)…`. Maybe I'm missing something. Could you elaborate on this? Regards, Michel

Michel Morin wrote:
Daryle Walker wrote:
However, every operation required for a noexcept expression is considered, including any destructor calls for temporary objects. That's why there's a "declval," after all. We need to call a constructor without a corresponding destructor, and the placement-new syntax (in a no-throw version) does that. The variant used is one of the few that's illegal to override.
In `MemberType(static_cast<T&&>(x)…)`, I don't see any any destruction of temporaries, since there are no temporaries involved in `static_cast<T&&>(x)…`. Maybe I'm missing something. Could you elaborate on this?
Ah, I see what I was missing. As Daryle said, the destruction of a MemberType temporary is invoked in noexcept operator. I didn't notice this, because clang does not evaluate the destructor. Thanks, Michel

Michel Morin wrote:
Ah, I see what I was missing. As Daryle said, the destruction of a MemberType temporary is invoked in noexcept operator. I didn't notice this, because clang does not evaluate the destructor.
Sorry, this is incorrect. Clang **does** checking the destructor in noexcept operator. I didn't know of N3204 (deducing noexcept for destructors), http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3204.htm and I made a wrong comment on clang's noexcept operator. As per N3204 (clang already implemented this), with the following type struct type { type() noexcept; ~type() { throw 0; } }; `noexcept(type())` should return true, despite the fact that the destructor throws. Regards, Michel

Date: Tue, 21 Feb 2012 20:47:33 +0900 From: Michel
Michel Morin wrote:
Ah, I see what I was missing. As Daryle said, the destruction of a MemberType temporary is invoked in noexcept operator. I didn't notice this, because clang does not evaluate the destructor.
Sorry, this is incorrect. Clang **does** checking the destructor in noexcept operator.
I didn't know of N3204 (deducing noexcept for destructors), http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3204.htm and I made a wrong comment on clang's noexcept operator.
As per N3204 (clang already implemented this), with the following type
struct type { type() noexcept; ~type() { throw 0; } };
`noexcept(type())` should return true, despite the fact that the destructor throws.
Explicitly adding a "noexcept(false)" to the destructor (which may be a good idea) would change "noexcept(type())" to false, right? The global-void*-new method should never consider the destructor in noexcept evalutations. (I originally had "never considers" instead of "should never consider," but I don't know how delegating constructors interact with new. If a new call craps out during the constructor phase, the destructor shouldn't be called, since the object was never fully initiated. But that's not the case with delegating constructors; they're complete as soon as the first (non-delegating?) sibling call completes. Does anyone know the C++11 policy on these interactions?) Daryle W.

Daryle Walker wrote:
As per N3204 (clang already implemented this), with the following type
struct type { type() noexcept; ~type() { throw 0; } };
`noexcept(type())` should return true, despite the fact that the destructor throws.
Explicitly adding a "noexcept(false)" to the destructor (which may be a good idea) would change "noexcept(type())" to false, right?
Right!
The global-void*-new method should never consider the destructor in noexcept evalutations.
This seems the right way. Dave also suggested to use placement new in libstdc++'s <type_traits>. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 Regards, Michel

Le 17/02/12 08:46, Daryle Walker a écrit :
From: me Date: Wed, 15 Feb 2012 23:19:46 -0500
From: me Date: Tue, 14 Feb 2012 11:08:10 -0500
[SNIP]
Any ideas for a fix? Does there need to be explicitly declared copy (and move) constructors?
I asked about this on StackOverflow, and we've discovered a new C++ gotcha. If we have a universal constructor: [SNIP]> Although constructor templates are ignored when determining if the automatic copy/move-constructors are made, they are NOT ignored when overload resolution needs to be done! If you're copying from a non-const object, the universal constructor will match a "MyType&" before the copy constructor's "MyType const&" would! This is what's causing the conflict. The way around it is to add an "unused" EnableIf template parameter to the constructor template that cancels the template when Args is a single argument and the argument's type is MyType. I'll work that in. I did it in (https://svn.boost.org/trac/boost/changeset/77046), so check if it works for you now. Of course, if you or someone else here has a better construction, let me know and I'll try it instead. (It still has to work for me on GCC-4.6, though.) Daryle W.
Hi, it is working for me now. Thanks for fixing this, Vicente
participants (4)
-
Daryle Walker
-
Michel Morin
-
Stephan T. Lavavej
-
Vicente J. Botet Escriba