Question

I need to create a predicate from bound member function, so I wrapped it in a boost::function<bool(SomeObject const &)>. That seems to be fine and everything, but I also needed to negate it in one case. However

boost::function<bool(SomeObject const &)> pred;
std::not1(pred);

does not compile under MSVC++ 9.0 (Visual Studio 2008), complaining that reference to reference is invalid:

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(213) : warning C4181: qualifier applied to reference type; ignored
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(213) : error C2529: '_Left' : reference to reference is illegal

The problem is that boost::function defines the argument_type as SomeObject const & and the std::unary_negate<_Fn1> instantiated by std::not1 internally tries to use const typename _Fn1::argument_type& and compiler rejects it because T::argument_type is already a reference. I am certain that that should compile under C++11, but this is old compiler that is C++03 only. So I'd like to know who's fault it is:

  • the compiler's, because it should collapse the reference (apparently not),
  • the standard library's, because it should be prepared to handle functors taking references (apparently not, because the specification defines unary_negate with const typename Predicate::argument_type& x argument),
  • boost's, because argument_type shouldn't be reference even when the actual argument is or
  • mine, because boost::function shouldn't be used with reference arguments?
Was it helpful?

Solution

The fault is certainly not Boost's; boost::function is basically just std::function, with all the same semantics. And boost::functions with reference parameters work fine, too. You just can't use them with std::not1 or the rest of the <functional> stuff.

C++11's reference-collapsing makes std::not1 work the way you would think it ought to. The way std::not1 was specified in C++03 couldn't possibly work without reference-collapsing — except in implementations where the implementors did a little bit of creative interpretation rather than slavishly following the letter of the Standard.

It's possible to make std::not1 work in C++03 by adding a specialization of std::unary_negate for predicates with reference argument_types, but neither libc++ nor libstdc++ has done so.

But you know who has? Boost! If you just change your code to use boost::not1 everywhere you currently use std::not1, everything will work fine. Basically, think of the boost namespace as if it were a C++11-compliant version of std; anything that works in C++11's std namespace probably works in C++03's boost namespace.


Caveat, hopefully off-topic: The Clang compiler on my Macbook (Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)) silently collapses references even in -std=c++03 mode, so that

typedef const int& ref;
typedef const ref& ref2;

produces no error. When you test your C++03 code, make sure you're not using a compiler with this misfeature.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top