1

See the below code,

The question is: how can I delay the construction of an object that is non-copyable, using optional<>.

I'm using boost::optional in the example, although I believe its now in the std::optional standard too.

Yes, I could use scoped_ptr<>, however I wanted to allocate on the stack, not the heap.

#include <boost/optional.hpp>
#include <boost/utility.hpp>

using namespace boost;

struct HardFoo : noncopyable { };

int main()
{
   optional<HardFoo> ok_1( in_place() ); // OK
   // optional<HardFoo> no_1( HardFoo() );  // won't compile

   optional<HardFoo> delay_construct;
   // delay_construct = HardFoo(); // won't compile
   // delay_construct = optional<HardFoo>( in_place() ); // won't compile
   // delay_construct.swap( optional<HardFoo>( in_place() ) ); // won't compile

   return 0;
}

I'm using g++, I assume it wouldn't matter whether its C++03 or C++11 in this case, as its a fundamental design issue rather than just a stuff up in the code.

As requested, some error messages, for this one, I uncommented:

delay_construct = HardFoo();

$ g++ -g -Wall -o test -I/stuff/boost/ test.cpp
In file included from /stuff/boost/utility.hpp:18:0,
                 from test.cpp:2:
test.cpp: In instantiation of ‘void boost::optional_detail::optional_base<T>::assign_value(boost::optional_detail::optional_base<T>::argument_type, boost::optional_detail::optional_base<T>::is_not_reference_tag) [with T = HardFoo; boost::optional_detail::optional_base<T>::argument_type = const HardFoo&; boost::optional_detail::optional_base<T>::is_not_reference_tag = mpl_::bool_<false>]’:
/stuff/boost/optional/optional.hpp:307:12:   required from ‘void boost::optional_detail::optional_base<T>::assign(boost::optional_detail::optional_base<T>::argument_type) [with T = HardFoo; boost::optional_detail::optional_base<T>::argument_type = const HardFoo&]’
/stuff/boost/optional/optional.hpp:606:9:   required from ‘boost::optional<T>& boost::optional<T>::operator=(boost::optional<T>::argument_type) [with T = HardFoo; boost::optional<T> = boost::optional<HardFoo>; boost::optional<T>::argument_type = const HardFoo&]’
test.cpp:14:30:   required from here
/stuff/boost/noncopyable.hpp:28:26: error: ‘const boost::noncopyable_::noncopyable& boost::noncopyable_::noncopyable::operator=(const boost::noncopyable_::noncopyable&)’ is private
test.cpp:6:8: error: within this context
In file included from /stuff/boost/optional.hpp:15:0,
                 from test.cpp:1:
/stuff/boost/optional/optional.hpp:433:69: note: synthesized method ‘HardFoo& HardFoo::operator=(const HardFoo&)’ first required here 
In file included from /stuff/boost/utility.hpp:18:0,
                 from test.cpp:2:
test.cpp: In instantiation of ‘void boost::optional_detail::optional_base<T>::construct(boost::optional_detail::optional_base<T>::argument_type) [with T = HardFoo; boost::optional_detail::optional_base<T>::argument_type = const HardFoo&]’:
/stuff/boost/optional/optional.hpp:308:12:   required from ‘void boost::optional_detail::optional_base<T>::assign(boost::optional_detail::optional_base<T>::argument_type) [with T = HardFoo; boost::optional_detail::optional_base<T>::argument_type = const HardFoo&]’
/stuff/boost/optional/optional.hpp:606:9:   required from ‘boost::optional<T>& boost::optional<T>::operator=(boost::optional<T>::argument_type) [with T = HardFoo; boost::optional<T> = boost::optional<HardFoo>; boost::optional<T>::argument_type = const HardFoo&]’
test.cpp:14:30:   required from here
/stuff/boost/noncopyable.hpp:27:7: error: ‘boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable&)’ is private
test.cpp:6:8: error: within this context
In file included from /stuff/boost/optional.hpp:15:0,
                 from test.cpp:1:
/stuff/boost/optional/optional.hpp:346:8: note: synthesized method ‘HardFoo::HardFoo(const HardFoo&)’ first required here 

There is an answer suggesting to use in_place directly, it works with this:

   optional<HardFoo> ok( in_place() );

but not this:

   optional<HardFoo> no( in_place<HardFoo>() ); // BAD

The error messages:

$ g++ -g -Wall -o test -I/stuff/boost/ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:15:44: error: no matching function for call to ‘in_place()’
test.cpp:15:44: note: candidates are:
In file included from /stuff/boost/preprocessor/iteration/detail/iter/forward1.hpp:52:0,
                 from /stuff/boost/utility/in_place_factory.hpp:24,
                 from /stuff/boost/optional/optional.hpp:37,
                 from /stuff/boost/optional.hpp:15,
                 from test.cpp:1:
/stuff/boost/utility/in_place_factory.hpp:73:1: note: template<class A0> boost::in_place_factory1<A0> boost::in_place(const A0&)
/stuff/boost/utility/in_place_factory.hpp:73:1: note:   template argument deduction/substitution failed:
test.cpp:15:44: note:   candidate expects 1 argument, 0 provided
In file included from /stuff/boost/preprocessor/iteration/detail/iter/forward1.hpp:57:0,
                 from /stuff/boost/utility/in_place_factory.hpp:24,
                 from /stuff/boost/optional/optional.hpp:37,
                 from /stuff/boost/optional.hpp:15,
                 from test.cpp:1:
/stuff/boost/utility/in_place_factory.hpp:73:1: note: template<class A0, class A1> boost::in_place_factory2<A0, A1> boost::in_place(const A0&, const A1&)
/stuff/boost/utility/in_place_factory.hpp:73:1: note:   template argument deduction/substitution failed:
test.cpp:15:44: note:   candidate expects 2 arguments, 0 provided
In file included from /stuff/boost/preprocessor/iteration/detail/iter/forward1.hpp:62:0,
                 from /stuff/boost/utility/in_place_factory.hpp:24,
                 from /stuff/boost/optional/optional.hpp:37,
                 from /stuff/boost/optional.hpp:15,
                 from test.cpp:1:
elegant dice
  • 1,307
  • 12
  • 19
  • When you say *won't compile* you should tell us what the compiler message is. Also, whether you are using C++03 or C++11 the easiest solution may differ. – Matthieu M. Aug 16 '13 at 14:09
  • The reason it doesn't compile, is because it would be a copy-construction. And the class is noncopyable. – elegant dice Aug 16 '13 at 14:17
  • It depends on the version of your compiler and the options you are using, in C++11 the class could be *move-constructible* and a number of examples should compile then (depending on whether `boost::noncopyable` has been updated to provide move constructors/assignment operator). – Matthieu M. Aug 16 '13 at 14:34
  • I see, well I'll be on C++03 for a few more months until I can also move from MSVC-2010 to MSVC-2012 (my other compiler). – elegant dice Aug 16 '13 at 14:36

2 Answers2

3

You need to in_place directly into the object:

delay_construct = boost::in_place<Type>(params);

Note that it appears that boost didn't support default construction through factories (nullary factories) until 1.35.

Mark B
  • 95,107
  • 10
  • 109
  • 188
3

In C++14, we will have std::optional, which happens to have std::optional::emplace. So you can do:

std::optional<HardFoo> delay_construct;
delay_construct.emplace(constructor_arg_1, constructor_arg_2);
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173