Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

lightweight_test

Header <boost/core/lightweight_test.hpp>
no_exceptions_support
noncopyable
null_deleter
ref
scoped_enum
swap
typeinfo

Authors

  • Peter Dimov
  • Beman Dawes

The header <boost/core/lightweight_test.hpp> is a lightweight test framework. It's useful for writing Boost regression tests for components that are dependencies of Boost.Test.

When using lightweight_test.hpp, do not forget to return boost::report_errors() from main.

#define BOOST_TEST(expression) /*unspecified*/
#define BOOST_TEST_NOT(expression) /*unspecified*/
#define BOOST_ERROR(message) /*unspecified*/
#define BOOST_TEST_EQ(expr1, expr2) /*unspecified*/
#define BOOST_TEST_NE(expr1, expr2) /*unspecified*/
#define BOOST_TEST_CSTR_EQ(expr1, expr2) /*unspecified*/
#define BOOST_TEST_CSTR_NE(expr1, expr2) /*unspecified*/
#define BOOST_TEST_ALL_EQ(begin1, end1, begin2, end2) /* unspecified */
#define BOOST_TEST_ALL_WITH(begin1, end1, begin2, end2, predicate) /* unspecified */
#define BOOST_TEST_THROWS(expr, excep) /*unspecified*/

namespace boost
{
    int report_errors();
}
BOOST_TEST(expression)

If expression is false increases the error count and outputs a message containing expression.

BOOST_TEST_NOT(expression)

If expression is true increases the error count and outputs a message containing !(expression).

BOOST_ERROR(message)

Increases error count and outputs a message containing message.

BOOST_TEST_EQ(expr1, expr2)

If expr1 != expr2 increases the error count and outputs a message containing both expressions.

BOOST_TEST_NE(expr1, expr2)

If expr1 == expr2 increases the error count and outputs a message containing both expressions.

BOOST_TEST_CSTR_EQ(expr1, expr2)

Specialization of BOOST_TEST_EQ which interprets expr1 and expr2 as pointers to null-terminated byte strings (C strings). If std::strcmp(expr1, expr2) != 0, increase the error count and output a message containing both expressions.

BOOST_TEST_CSTR_NE(expr1, expr2)

Specialization of BOOST_TEST_NE which interprets expr1 and expr2 as pointers to null-terminated byte strings (C strings). If std::strcmp(expr1, expr2) == 0, increase the error count and output a message containing both expressions.

BOOST_TEST_ALL_EQ(begin1, end1, begin2, end2)

Compares the content of two sequences. If they have different sizes, or if any pairwise element differs, increases the error count and outputs a message containing at most 8 differing elements.

BOOST_TEST_ALL_WITH(begin1, end1, begin2, end2, predicate)

Compares the content of two sequences. If they have different sizes, or if any pairwise element do not fulfill the binary predicate, increases the error count and outputs a message containing at most 8 differing elements.

BOOST_TEST_THROWS(expr, excep)

If BOOST_NO_EXCEPTIONS is not defined and if expr does not throw an exception of type excep, increases the error count and outputs a message containing the expression.

If BOOST_NO_EXCEPTIONS is defined, this macro expands to nothing and expr is not evaluated.

int boost::report_errors()

Return the error count from main.

#include <boost/core/lightweight_test.hpp>

int sqr( int x )
{
    return x * x;
}

int main()
{
    BOOST_TEST( sqr(2) == 4 );
    BOOST_TEST_EQ( sqr(-3), 9 );

    return boost::report_errors();
}

The header <boost/core/lightweight_test_trait.hpp> defines a couple of extra macros for testing compile-time traits that return a boolean value.

#define BOOST_TEST_TRAIT_TRUE((Trait)) /*unspecified*/
#define BOOST_TEST_TRAIT_FALSE((Trait)) /*unspecified*/
BOOST_TEST_TRAIT_TRUE((Trait))

If Trait::value != true increases the error count and outputs a message containing Trait. Note the double set of parentheses; these enable Trait to contain a comma, which is common for templates.

BOOST_TEST_TRAIT_FALSE((Trait))

If Trait::value != false increases the error count and outputs a message containing Trait. Note the double set of parentheses.

#include <boost/core/lightweight_test_trait.hpp>
#include <boost/core/is_same.hpp>

template<class T, class U> struct X
{
    typedef T type;
};

using boost::core::is_same;

int main()
{
    BOOST_TEST_TRAIT_TRUE(( is_same<X<int, long>::type, int> ));

    return boost::report_errors();
}

Authors

  • Pavel Vozenilek

The header <boost/core/no_exceptions_support.hpp> defines macros for use in code that needs to be portable to environments that do not have support for C++ exceptions.

#define BOOST_TRY /*unspecified*/
#define BOOST_CATCH(x) /*unspecified*/
#define BOOST_CATCH_END /*unspecified*/
#define BOOST_RETHROW /*unspecified*/
void foo() {
  BOOST_TRY {
    ...
  } BOOST_CATCH(const std::bad_alloc&) {
      ...
      BOOST_RETHROW
  } BOOST_CATCH(const std::exception& e) {
      ...
  }
  BOOST_CATCH_END
}

With exception support enabled it will expand into:

void foo() {
  { try {
    ...
  } catch (const std::bad_alloc&) {
      ...
      throw;
  } catch (const std::exception& e) {
      ...
  }
  }
}

With exception support disabled it will expand into:

void foo() {
  { if(true) {
    ...
  } else if (false) {
      ...
  } else if (false)  {
      ...
  }
  }
}

Authors

  • Dave Abrahams

The header <boost/noncopyable.hpp> defines the class boost::noncopyable. It is intended to be used as a private base. boost::noncopyable has private (under C++03) or deleted (under C++11) copy constructor and a copy assignment operator and can't be copied or assigned; a class that derives from it inherits these properties.

boost::noncopyable was originally contributed by Dave Abrahams.

namespace boost
{
    class noncopyable;
}
#include <boost/core/noncopyable.hpp>

class X: private boost::noncopyable
{
};

Class noncopyable has protected constructor and destructor members to emphasize that it is to be used only as a base class. Dave Abrahams notes concern about the effect on compiler optimization of adding (even trivial inline) destructor declarations. He says:

Probably this concern is misplaced, because noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics.

With C++2011, using an optimized and trivial constructor and similar destructor can be enforced by declaring both and marking them default. This is done in the current implementation.

Authors

  • Andrey Semashev

The header <boost/core/null_deleter.hpp> defines the boost::null_deleter function object, which can be used as a deleter with smart pointers such as unique_ptr or shared_ptr. The deleter doesn't do anything with the pointer provided upon deallocation, which makes it useful when the pointed object is deallocated elsewhere.

std::shared_ptr< std::ostream > make_stream()
{
    return std::shared_ptr< std::ostream >(&std::cout, boost::null_deleter());
}

ref

Authors

  • Jaakko Järvi
  • Peter Dimov
  • Douglas Gregor
  • Dave Abrahams
  • Frank Mori Hess
  • Ronald Garcia

The Ref library is a small library that is useful for passing references to function templates (algorithms) that would usually take copies of their arguments. It defines the class template boost::reference_wrapper<T>, two functions boost::ref and boost::cref that return instances of boost::reference_wrapper<T>, a function boost::unwrap_ref that unwraps a boost::reference_wrapper<T> or returns a reference to any other type of object, and the two traits classes boost::is_reference_wrapper<T> and boost::unwrap_reference<T>.

The purpose of boost::reference_wrapper<T> is to contain a reference to an object of type T. It is primarily used to "feed" references to function templates (algorithms) that take their parameter by value.

To support this usage, boost::reference_wrapper<T> provides an implicit conversion to T&. This usually allows the function templates to work on references unmodified.

boost::reference_wrapper<T> is both CopyConstructible and Assignable (ordinary references are not Assignable).

The expression boost::ref(x) returns a boost::reference_wrapper<X>(x) where X is the type of x. Similarly, boost::cref(x) returns a boost::reference_wrapper<X const>(x).

The expression boost::unwrap_ref(x) returns a boost::unwrap_reference<X>::type& where X is the type of x.

The expression boost::is_reference_wrapper<T>::value is true if T is a reference_wrapper, and false otherwise.

The type-expression boost::unwrap_reference<T>::type is T::type if T is a reference_wrapper, T otherwise.

Reference

namespace boost {
  template<typename T> class reference_wrapper;

  template<typename T> struct is_reference_wrapper;
  template<typename T> struct unwrap_reference;
  template<typename T> reference_wrapper< T > const ref(T &);
  template<typename T> reference_wrapper< T const  > const cref(T const &);
  template<typename T> void ref(T const &&);
  template<typename T> void cref(T const &&);
  template<typename T> unwrap_reference< T >::type & unwrap_ref(T &);
}

ref and cref were originally part of the Tuple library by Jaakko Järvi. They were "promoted to boost:: status" by Peter Dimov because they are generally useful. Douglas Gregor and Dave Abrahams contributed is_reference_wrapper and unwrap_reference. Frank Mori Hess and Ronald Garcia contributed boost::unwrap_ref.

Authors

  • Beman Dawes
  • Vicente J. Botet Escriba
  • Anthony Williams

The boost/core/scoped_enum.hpp header contains a number of macros that can be used to generate C++11 scoped enums (7.2 [dcl.enum]) if the feature is supported by the compiler, otherwise emulate it with C++03 constructs. The BOOST_NO_CXX11_SCOPED_ENUMS macro from Boost.Config is used to detect the feature support in the compiler.

Some of the enumerations defined in the standard library are scoped enums.

enum class future_errc
{
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
};

The user can portably declare such enumeration as follows:

BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
{
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
}
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)

These macros allows to use future_errc in almost all the cases as an scoped enum.

future_errc ev = future_errc::no_state;

It is possible to specify the underlying type of the enumeration:

BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(future_errc, unsigned int)
{
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
}
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)

The enumeration supports explicit conversion from the underlying type.

The enumeration can be forward declared:

BOOST_SCOPED_ENUM_FORWARD_DECLARE(future_errc);

There are however some limitations. First, the emulated scoped enum is not a C++ enum, so is_enum< future_errc > will be false_type.

Second, the emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some helpers. Instead of

switch (ev)
{
case future_errc::broken_promise:
    // ...

use

switch (boost::native_value(ev))
{
case future_errc::broken_promise:
    // ...

and instead of

template <>
struct is_error_code_enum< future_errc > :
    public true_type
{
};

use

template <>
struct is_error_code_enum< BOOST_SCOPED_ENUM_NATIVE(future_errc) > :
    public true_type
{
};

Lastly, explicit conversion to the underlying type should be performed with boost::underlying_cast instead of static_cast:

unsigned int val = boost::underlying_cast< unsigned int >(ev);

Here is usage example:

BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(algae, char)
{
    green,
    red,
    cyan
}
BOOST_SCOPED_ENUM_DECLARE_END(algae)
...
algae sample( algae::red );
void foo( algae color );
...
sample = algae::green;
foo( algae::cyan );

In early versions of the header there were two ways to declare scoped enums, with different pros and cons to each. The other way used a different set of macros:

BOOST_SCOPED_ENUM_START(algae)
{
    green,
    red,
    cyan
};
BOOST_SCOPED_ENUM_END
...
BOOST_SCOPED_ENUM(algae) sample( algae::red );
void foo( BOOST_SCOPED_ENUM(algae) color );
...
sample = algae::green;
foo( algae::cyan );

Here BOOST_SCOPED_ENUM_START corresponds to BOOST_SCOPED_ENUM_DECLARE_BEGIN, BOOST_SCOPED_ENUM_END to BOOST_SCOPED_ENUM_DECLARE_END and BOOST_SCOPED_ENUM to BOOST_SCOPED_ENUM_NATIVE. Note also the semicolon before BOOST_SCOPED_ENUM_END.

In the current version these macros produce equivalent result to the ones described above and are considered deprecated.

The header boost/core/underlying_type.hpp defines the metafunction boost::underlying_type which can be used to obtain the underlying type of the scoped enum. This metafunction has support for emulated scoped enums declared with macros in boost/core/scoped_enum.hpp. When native scoped enums are supported by the compiler, this metafunction is equivalent to std::underlying_type.

Unfortunately, there are configurations which implement scoped enums but not std::underlying_type. In this case boost::underlying_type has to be specialized by user. The macro BOOST_NO_UNDERLYING_TYPE is defined to indicate such cases.

This scoped enum emulation was developed by Beman Dawes, Vicente J. Botet Escriba and Anthony Williams.

Helpful comments and suggestions were also made by Kjell Elster, Phil Endecott, Joel Falcou, Mathias Gaunard, Felipe Magno de Almeida, Matt Calabrese, Daniel James and Andrey Semashev.

Authors

  • Niels Dekker
  • Joseph Gauterin
  • Steven Watanabe
  • Eric Niebler

template<class T> void swap(T& left, T& right);

The template function boost::swap allows the values of two variables to be swapped, using argument dependent lookup to select a specialized swap function if available. If no specialized swap function is available, std::swap is used.

The generic std::swap function requires that the elements to be swapped are assignable and copy constructible. It is usually implemented using one copy construction and two assignments - this is often both unnecessarily restrictive and unnecessarily slow. In addition, where the generic swap implementation provides only the basic guarantee, specialized swap functions are often able to provide the no-throw exception guarantee (and it is considered best practice to do so where possible [1].

The alternative to using argument dependent lookup in this situation is to provide a template specialization of std::swap for every type that requires a specialized swap. Although this is legal C++, no Boost libraries use this method, whereas many Boost libraries provide specialized swap functions in their own namespaces.

boost::swap also supports swapping built-in arrays. Note that std::swap originally did not do so, but a request to add an overload of std::swap for built-in arrays has been accepted by the C++ Standards Committee[2].

boost::swap provides the same exception guarantee as the underlying swap function used, with one exception; for an array of type T[n], where n > 1 and the underlying swap function for T provides the strong exception guarantee, boost::swap provides only the basic exception guarantee.

Either:

  • T must be assignable
  • T must be copy constructible

Or:

  • A function with the signature swap(T&,T&) is available via argument dependent lookup

Or:

  • A template specialization of std::swap exists for T

Or:

  • T is a built-in array of swappable elements

Several older compilers do not support argument dependent lookup. On these compilers boost::swap will call std::swap, ignoring any specialized swap functions that could be found as a result of argument dependent lookup.

  • Niels Dekker - for implementing and documenting support for built-in arrays
  • Joseph Gauterin - for the initial idea, implementation, tests, and documentation
  • Steven Watanabe - for the idea to make boost::swap less specialized than std::swap, thereby allowing the function to have the name 'swap' without introducing ambiguity

Authors

  • Peter Dimov

The header <boost/core/typeinfo.hpp> defines a class boost::core::typeinfo, which is an alias for std::type_info when RTTI is enabled, and is a reasonable substitute when RTTI is not supported.

The macro BOOST_CORE_TYPEID, when applied to a type T, is the equivalent of typeid(T) and produces a reference to a const typeinfo object.

The function boost::core::demangled_name takes a boost::core::typeinfo const & ti and either returns ti.name(), when that string doesn't need to be demangled, or boost::core::demangle(ti.name()), when it does. The return type of boost::core::demangled_name is char const* in the first case and std::string in the second.

namespace boost
{

namespace core
{
    class typeinfo;
    /* char const* or std::string */ demangled_name( typeinfo const & ti );
}

}

#define BOOST_CORE_TYPEID(T) /*unspecified*/
#include <boost/core/typeinfo.hpp>
#include <iostream>

template<class T1, class T2> struct X
{
};

int main()
{
    typedef X<void const*, void(*)(float)> T;

    boost::core::typeinfo const & ti = BOOST_CORE_TYPEID(T);

    std::cout << boost::core::demangled_name( ti ) << std::endl;
}


[1] Scott Meyers, Effective C++ Third Edition, Item 25: "Consider support for a non-throwing swap"


PrevUpHomeNext