1

When trying to build some legacy code (with a recent version of boost), I stumbled upon the following problem:

#include <boost/scoped_array.hpp>

bool foo(const boost::scoped_array<int> bar) {
    return bar;
}

bool foo2(const boost::scoped_array<int> bar) {
    const bool r = bar;
    return r;
}

bool foo3(const boost::scoped_array<int> bar) {
    return bar ? true : false;
}

The above source will not compile. Both foo and foo2 are erroneous. To be precise, the expected implicit conversion from scoped_array to bool is not allowed:

➜  /tmp clang++ --std=c++14 testconversion.cpp -o testconversion.o
testconversion.cpp:4:12: error: no viable conversion from returned value of type 'const boost::scoped_array<int>' to function return type 'bool'
    return bar;
           ^~~
testconversion.cpp:8:16: error: no viable conversion from 'const boost::scoped_array<int>' to 'const bool'
    const bool r = bar;

This brings up two questions:

  1. Why are foo and foo2 not valid? the reference explicitly mentions:

    when initializing a new object of type T2, including return statement in a function returning T2;

  2. When was that legal. The legacy code definitely used to build with boost 1.48.0. Was there
    1. a change in the boost libraries
    2. a change to the language/compilers
choeger
  • 3,562
  • 20
  • 33

1 Answers1

3

Look inside the documentation of boost::scoped_array:

operator unspecified-bool-type () const; // never throws

Returns an unspecified value that, when used in boolean contexts, is equivalent to get() != 0.

You have to use static_cast to convert your boost::scoped_array to bool:

bool foo(const boost::scoped_array<int>& bar) {
    return static_cast<bool>(bar);
}

bool foo2(const boost::scoped_array<int>& bar) {
    const bool r = static_cast<bool>(bar);
    return r;
}

Maybe just a typo but in your example you passing boost::scoped_array by value. It has no copy constructor, so passing it by value will also cause errors.


It works with Boost 1.48.0 because the operator_bool.hpp was different in that version. In Boost 1.64.0 the same header contains explicit operator bool () const; which prevenst you to copy-initialize a bool from a boost::scoped_array instance when you are compiling it with -std=c++14 (or -std=c++11). Your code will work with Boost 1.64.0 too if you are compiling it with -std=c++98.

Akira
  • 4,385
  • 3
  • 24
  • 46
  • 1
    Thanks for finding the root cause. That was very helpful. – choeger Jun 20 '17 at 08:19
  • 1
    In particular, the erroneous code assumes two implicit conversions (to `unspecified-bool-type` and then to `bool`) in a row. That's not allowed. Making the second conversion explicit solves it. – MSalters Jun 20 '17 at 08:48