[utility] Any interest for a macro which automatically creates default move-semantics, comparisson etc for a class
I've created a macro which automatically creates: - move constructor\assignment - swap member function - operator== and operator!= - operator< - assignment operator without side-effects if it throws. Example usage: class Foo { public: Foo() {} DEFAULT_EVERYTHING(Foo, ( (int)(a) ) ( (std::vector<int>)(b) ) ( (float)(c) ) ); }; Any interest, suggestions or ideas? Ofcourse it might be split into several macros depending on what operators the class requests (if it's a move-only class etc), and perhaps an extra parameter enable if a member is up for sorting and comparison. Code available here: https://www.dropbox.com/s/dhkxj94rrh83az0/DefaultEverything.h
2013/11/6 Viktor Sehr
I've created a macro which automatically creates: - move constructor\assignment - swap member function - operator== and operator!= - operator< - assignment operator without side-effects if it throws.
Example usage: class Foo { public: Foo() {} DEFAULT_EVERYTHING(Foo, ( (int)(a) ) ( (std::vector<int>)(b) ) ( (float)(c) ) ); };
Any interest, suggestions or ideas? Ofcourse it might be split into several macros depending on what operators the class requests (if it's a move-only class etc), and perhaps an extra parameter enable if a member is up for sorting and comparison.
Code available here: https://www.dropbox.com/s/dhkxj94rrh83az0/DefaultEverything.h
Looks pretty interesting, however there is a room for improvement: * boost::swap is more optimal than ::std::swap (or just allow ADL during swap) * std::move vs boost::move? * marking generated functions with BOOST_NOEXCEPT when possible. That's the place when DEFAULT_EVERYTHING macro could be really helpful. In your example all the types in Foo have noexcept moves and swaps, so at least all moves and swap of Foo must be also marked with noexcept -- Best regards, Antony Polukhin
Thanks for the response, I've updated the class to utilize boost::swap, boost::move and also marked move\swap function as noexcept. I'm thinking about extending it for pod-classes (only provide comparisson\sort) and perhaps move-only classes. Also perhaps a constructor which takes all member variables as parameters (especially in the pod-case it's probably useful)? /Viktor
2013/11/7 Viktor Sehr
Thanks for the response, I've updated the class to utilize boost::swap, boost::move and also marked move\swap function as noexcept.
Marking methods with BOOST_NOEXCEPT by default is not the right way. noexcept specification depends on types that are stored in class, so noexcept specification of methods must be detected using TypeTraits and other magic. Something like this: BOOST_NOEXCEPT_IF(/*some expression to detect that operations for type 1 won't throw, like `boost::is_nothrow_move_constructible<Type1>::value`*/ && /*same stuff for all other types*/ ) This is a lot of work to do... But it is not critical at the moment. Following issues must be solved before the macro could be officially reviewed by community: * Header DefaultEverything.h requires include guards, hpp extension and must be lower-case. * DEFAULT_EVERYTHING does not creates a copy constructor. * There are some policies that must be followed: http://www.boost.org/development/requirements.html For example all the macro must have BOOST_ prefix and so on. * tests must be provided I'm thinking about extending it for pod-classes (only provide
comparisson\sort) and perhaps move-only classes. Also perhaps a constructor which takes all member variables as parameters (especially in the pod-case it's probably useful)?
Sounds not bad. I'd also like to have a macro that generates move assignment and assignment operators using member swap and constructors. Something like the following: #define BOOST_GENERATE_ASSIGNMENTS(classname) \ classname& operator=(BOOST_COPY_ASSIGN_REF(classname) other) \ BOOST_NOEXCEPT_IF(boost::is_nothrow_constructible<classname>::value \ && boost::is_nothrow_member_swappable<classname>::value) \ { \ classname(other).swap(*this); \ return *this; \ } \ classname& operator=(BOOST_RV_REF(classname) other) \ BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<classname>::value \ && boost::is_nothrow_member_swappable<classname>::value) \ { \ classname(boost::move(other)).swap(*this); \ return *this; \ } \ /**/ -- Best regards, Antony Polukhin
I omitted the copyconstructor as it's generated by the compiler. I updated the class to utilize BOOST_NOEXCEPT_IF for each member, also I renamed the macro to BOOST_DEFAULT_CLASS (which I think is a better name). I kept the original file name right now as I dont want to change the link. I will add BOOST_DEFAULT_POD_CLASS and BOOST_DEFAULT_MOVABLE_CLASS and a constructor which takes all the parameters. I think the problem with utilizing the member swap is that it doesnt work with integers etc
On 11/06/2013 06:38 PM, Viktor Sehr wrote:
Example usage: class Foo { public: Foo() {} DEFAULT_EVERYTHING(Foo, ( (int)(a) ) ( (std::vector<int>)(b) ) ( (float)(c) ) ); };
Any interest, suggestions or ideas?
(vector2
(member, other.member)), swap_functor()); }
If we are going to specify the member variables in a funny way, it may
be worth considering a solution based on Boost.Fusion. For example,
swap() can be made like this:
class Foo {
public:
Foo()
{
member.a = 0;
member.c = 0.0;
}
// swap and swap_functor should be turned into a macro
public:
void swap(Foo& other)
{
using namespace boost::fusion;
for_each(zip_view< vector2
Is it possible to do this without having to specify a base class ('member') for the variables? If we are going to specify the member variables in a funny way, it may
be worth considering a solution based on Boost.Fusion. For example, swap() can be made like this:
class Foo { public: Foo() { member.a = 0; member.c = 0.0; }
I've updated the class with the following additions (Link: http://bit.ly/HFEr2Q): - Renamed macro to BOOST_DEFAULT - Append serialized version of class to std::ostream (for use when overloading global operator<<) - Abbreviations to remove some generated function (BOOST_DEFAULT_NO_COMPARE, BOOST_DEFAULT_NO_COPY) etc - Cleaned up code Issues still is - I'm not sure what to look for when marking move-assign, move-construct no-throw as I am using std::swap internally, perhaps has_nothrow_constructor also? - All members needs parameterless constructor to work, I am not sure how to get around this as I'd like pod types to be swapped. - The parameter-constructor doesn't move-construct members (is this only possible with C++11?) Any new thought?
On 11/08/2013 04:29 PM, Viktor Sehr wrote:
Is it possible to do this without having to specify a base class ('member') for the variables?
Yes, there are two possibilities. First, you can define the member variables outside the class and let the class inherit the member variables. Second, you can declare the class and its member variables as normal, and then use BOOST_FUSION_ADAPT_STRUCT after the class definition to add reflection. However, this requires you to specify the member variables twice (in the class and in the adapter.)
participants (3)
-
Antony Polukhin
-
Bjorn Reese
-
Viktor Sehr