headmyshoulder / odeint-v2

odeint - solving ordinary differential equations in c++ v2
http://headmyshoulder.github.com/odeint-v2/
Other
337 stars 102 forks source link

boost::cref moved to global scope by odeint.hpp #190

Closed Wentzell closed 8 years ago

Wentzell commented 8 years ago

I am using boost version 1.60.

The following snippet

#include <boost/multi_array.hpp>
#include <boost/numeric/odeint.hpp>

using namespace std; 

class widget: public boost::multi_array<int, 1>
{}; 

int main()
{
   widget widg; 
   auto widg_ref = cref(widg); 
}

gives the compiler error (clang++-3.6)

test.cpp:12:20: error: call to 'cref' is ambiguous
   auto widg_ref = cref(widg); 
                   ^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:449:5: note: candidate function [with _Tp = widget]
    cref(const _Tp& __t) noexcept
    ^
/usr/local/include/boost/core/ref.hpp:150:80: note: candidate function [with T = widget]
template<class T> BOOST_FORCEINLINE reference_wrapper<T const> BOOST_REF_CONST cref( T const & t )
                                                                               ^

as apparently boost::cref is moved to the global scope? I want to only use std::cref though.

If I remove

#include <boost/numeric/odeint.hpp>

it compiles fine.

mariomulansky commented 8 years ago

are you compiling with C++11? Does it change if you add -std=c++11 to the compiler?

Wentzell commented 8 years ago

I did compile with

clang++-3.6 -std=c++11 -O1 test.cpp -o run
Wentzell commented 8 years ago

If I replace

class widget: public boost::multi_array<int, 1>
{}; 

with

class widget
{}; 

it compiles fine though. It seems to also be tied to the inheritance somehow..

mariomulansky commented 8 years ago

ah, interesting. can you add the following to check if odeint correctly understands the C++11 mode:

#ifdef BOOST_NUMERIC_ODEINT_CXX11
std::cout << "C++ 11" << std::endl;
#endif
Wentzell commented 8 years ago

I tried, BOOST_NUMERIC_ODEINT_CXX11 is set to 1, so it seems to understand.

headmyshoulder commented 8 years ago

Hi,

this seems like an ADL (argument dependent lookup) issue, but I am not sure. Can you try to specify cref explictly from std:

auto widg_ref = std::cref( widg );

The ambiguity might be due to fact that widg is type from the boost namespace. The cref version from boost is therefore also considered as a valid expression or overload.

On 17.02.2016 13:36, Wentzell wrote:

I am using boost version 1.60.

The following snippet

include <boost/multi_array.hpp>

include <boost/numeric/odeint.hpp>

using namespace std;

class widget: public boost::multi_array<int, 1> {};

int main() { widget widg; auto widg_ref = cref(widg); }

gives the compiler error (clang++-3.6)

|test.cpp:12:20: error: call to 'cref' is ambiguous auto widg_ref = cref(widg); ^~~~ /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:449:5: note: candidate function [with _Tp = widget] cref(const _Tp& __t) noexcept ^ /usr/local/include/boost/core/ref.hpp:150:80: note: candidate function [with T = widget] template BOOST_FORCEINLINE reference_wrapper BOOST_REF_CONST cref( T const & t ) ^ |

as apparently boost::cref is moved to the global scope? I want to only use std::cref though.

If I remove

include <boost/numeric/odeint.hpp>

it compiles fine.

— Reply to this email directly or view it on GitHub https://github.com/headmyshoulder/odeint-v2/issues/190.

mariomulansky commented 8 years ago

I agree, the fact that it works when removing the derivation from boost::multi_array<int, 1> strongly indicates it's ADL related. However, the problem also goes away when removing the odeint include, so it seems odeint somehow does include boost/ref.hpp, although it's not supposed to when compiling in C++11 modes. Now I did a quick search on the odeint sources and ref.hpp is only included from util/unwrap_reference.hpp and there it is guarded by BOOST_NUMERIC_ODEINT_CXX11. So maybe some other boost library that is used from odeint is pulling in boost/ref.hpp - this is rather hard to find out here.

That easiest workaround should be to just explicitly use std::cref. Another idea could be to not include odeint.hpp, but only the part really needed in the end. Maybe then boost/ref.hpp doesn't get pulled in.

headmyshoulder commented 8 years ago

On 17.02.2016 22:54, Mario Mulansky wrote:

I agree, the fact that it works when removing the derivation from |boost::multi_array<int, 1>| strongly indicates it's ADL related. However, the problem also goes away when removing the odeint include, so it seems odeint somehow does include |boost/ref.hpp|, although it's not supposed to when compiling in C++11 modes. Now I did a quick search on the odeint sources and |ref.hpp| is only included from |util/unwrap_reference.hpp| and there it is guarded by |BOOST_NUMERIC_ODEINT_CXX11|. So maybe some other boost library that is used from odeint is pulling in |boost/ref.hpp| - this is rather hard to find out here.

One can see the preprocessed source when compiling with -E . It seems that boost/ref ist included from some boost.fusion headers which are included in is_resizeable.

I don't know if this can somehow be avoided.

That easiest workaround should be to just explicitly use |std::cref|. Another idea could be to not include |odeint.hpp|, but only the part really needed in the end. Maybe then |boost/ref.hpp| doesn't get pulled in.

— Reply to this email directly or view it on GitHub https://github.com/headmyshoulder/odeint-v2/issues/190#issuecomment-185423988.

mariomulansky commented 8 years ago

Well I don't think there is much we can do about that... The only chance I see is to go to Boost.Fusion with this example, but including boost.fusion instead of odeint, which should give the same error. Maybe they can do something about this problem...

Wentzell commented 8 years ago

@headmyshoulder Yes it compiles just fine if I resolve the ambiguity by specifying std::cref. ADL seems very likely indeed.

@mariomulansky Indeed, the strange thing is that the ambiguity is tied to the inclusion of odeint. The workaround you proposed is what I am using right now in my project. I first thought I that I was missing some using directive hidden in my source files, but then I was able to reproduce the problem with the minimal example above. Would be nice to know where that boost/ref.hpp inclusion is coming from. I will have some a further look at the odeint sources myself when I find time.

Wentzell commented 8 years ago

Just read the last two posts, thanks! I will try posting the example there.

mariomulansky commented 8 years ago

ok great - good luck! I will close this here then.