Boost logo

Boost Users :

Subject: Re: [Boost-users] thread/call_once compile error on trunk on my code
From: Olaf Peter (ope-devel_at_[hidden])
Date: 2013-04-21 13:46:44


>> namespace {
>>
>> struct id_string
>> {
>> static boost::once_flag flag;
>> typedef std::map<int, std::string> map_type;
>> ...
>>
>> static void do_init(token_id_string& self)
>> {

Mmh, wrong reduced/generalized even if I checked carefully, should be

static void do_init(id_string& self) {
        insert(/* aka *this */self.m_map)(x, "y")(...)
}

But I see, you recognized this.

>> insert(self.m_map)(x, "y")(...)
>> ;
>> }
>>
>> std::string const& operator()(id::type id) const
>> {
>> boost::call_once(flag, &id_string::do_init, *this);
>>
>> map_iterator s = m_map.find(id);
>> ...
>> }
>> };
>>
> Hi,
>
> the error
> /usr/local/include/boost/thread/detail/invoke.hpp:406:65: error: invalid
> initialization of non-const reference of type '{anonymous}::id_string&'
> from an rvalue of type '{anonymous}::id_string'
>
> says you that the parameter (const) can not be used where a non-const is
> expected.
>
> Shouldn't the operator be declared non-const
>
> std::string const& operator()(id::type id) ;

The idea was to create a lazy lookup since this functor is only used on
debugging, but compiled/linked at all build targets (I know, project
structure ...). Imo making the member const/non-const is a taste of
matter; const since it does primary a lookup, non-const due to the lazy
initialization. So, I'm not sure.

> In addition if you want to pass a reference you would need to use
> boost::ref().
>
> The following compile well without the patch
>
> struct id_string
> {
> static boost::once_flag flag;
> static void do_init(id_string & )
> {}
> void operator()()
> {
> boost::call_once(flag, &id_string::do_init, boost::ref(*this));
> }
> };
>
> Note that the following compiles
>
> struct id_string
> {
> static boost::once_flag flag;
> static void do_init(id_string & )
> {}
> void operator()()
> {
> std::bind(&id_string::do_init, std::ref(*this))();
> }
> void operator()(int) const
> {
> std::bind(&id_string::do_init, *this)();
> }
> };
>
> I would expect that the preceding fails as *this is a 'id_string const&'
> and do_init expects an 'id_string &'.
> This would explain why with the patch it worked as the patch was calling
> to std::bind.
>
> But if make use of the class
>
> {
> id_string id;
> //id();
> id(1);
> }
>
> I get the following error
>
> gcc.compile.c++
> /tmp/bin.v2/boost/bin.v2/libs/thread/test/call_once_p.test/gcc-4.6.1.0x/debug/threading-multi/sync/mutual_exclusion/once/call_once/call_once_pass.o
>
> In file included from /usr/include/c++/4.6/functional:56:0,
> from ../../../boost/thread/detail/invoke.hpp:34,
> from ../../../boost/thread/pthread/once_atomic.hpp:17,
> from ../../../boost/thread/once.hpp:20,
> from sync/mutual_exclusion/once/call_once/call_once_pass.cpp:26:
> /usr/include/c++/4.6/tuple: In constructor ‘constexpr
> std::_Head_base<_Idx, _Head, false>::_Head_base(const _Head&) [with
> unsigned int _Idx = 0u, _Head = id_string]’:
> /usr/include/c++/4.6/tuple:162:44: instantiated from ‘constexpr
> std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const _Head&,
> const _Tail& ...) [with unsigned int _Idx = 0u, _Head = id_string, _Tail
> = {}]’
> /usr/include/c++/4.6/tuple:423:24: instantiated from ‘constexpr
> std::tuple<_T1>::tuple(const _T1&) [with _T1 = id_string]’
> /usr/include/c++/4.6/functional:1186:70: instantiated from
> ‘std::_Bind<_Functor(_Bound_args ...)>::_Bind(_Functor&&, _Args&& ...)
> [with _Args = {const id_string&}, _Functor = void (*)(id_string&),
> _Bound_args = {id_string}]’
> /usr/include/c++/4.6/functional:1450:41: instantiated from ‘typename
> std::_Bind_helper<_Functor, _ArgTypes>::type std::bind(_Functor&&,
> _ArgTypes&& ...) [with _Functor = void (*)(id_string&), _ArgTypes =
> {const id_string&}, typename std::_Bind_helper<_Functor,
> _ArgTypes>::type = std::_Bind<void (*(id_string))(id_string&)>]’
> sync/mutual_exclusion/once/call_once/call_once_pass.cpp:206:43:
> instantiated from here
> /usr/include/c++/4.6/tuple:97:25: erreur: use of deleted function
> ‘id_string::id_string(const id_string&)’
> sync/mutual_exclusion/once/call_once/call_once_pass.cpp:194:8: erreur:
> ‘id_string::id_string(const id_string&)’ is implicitly deleted because
> the default definition would be ill-formed:
> sync/mutual_exclusion/once/call_once/call_once_pass.cpp:194:8: erreur:
> use of deleted function ‘boost::once_flag::once_flag(const
> boost::once_flag&)’
> ../../../boost/thread/pthread/once_atomic.hpp:59:5: erreur: declared here
>
>
>
> Could you tell me if works for you after rolling back the patch and
> adding the suggested changes on your code?

you mean using boost::ref? I'm not sure if I have std::ref on my old gcc
compiler 4.6.3. Anyway, with thread/detail/invoke.hpp from Revision: 83985

         std::string const& operator()(id::type id)
         {
             boost::call_once(flag, &id_string::do_init, boost::ref(*this));

             map_iterator s = m_map.find(id);

             if (s == m_map.end()) {
                 return m_map[id::invalid];
             } else {
                 return s->second;
             }
             ...
         }

compiles, but not std::string const& operator()(id::type id) const,
neither with ref or cref.

Thanks,
Olaf


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net