diff --git a/doc/history.xml b/doc/history.xml
index a7f89df..05fddf8 100644
--- a/doc/history.xml
+++ b/doc/history.xml
@@ -22,6 +22,14 @@
Added a new header <boost/function/function_typeof.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects.
Added a new header <boost/function/function_fwd.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects.
+
+ The target()
+ function now respects the cv-qualifiers of function objects
+ stored by reference
+ (using boost::reference_wrapper), such
+ that a reference to a const
function object cannot
+ be accessed as a reference to a non-const
function
+ object.
diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp
index b74f43a..064fdde 100644
--- a/include/boost/function/function_base.hpp
+++ b/include/boost/function/function_base.hpp
@@ -18,7 +18,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -95,8 +97,15 @@ namespace boost {
mutable void* obj_ptr;
// For pointers to std::type_info objects
- // (get_functor_type_tag, check_functor_type_tag).
- const void* const_obj_ptr;
+ struct type_t {
+ // (get_functor_type_tag, check_functor_type_tag).
+ const std::type_info* type;
+
+ // Whether the type is const-qualified.
+ bool const_qualified : 1;
+ // Whether the type is volatile-qualified.
+ bool volatile_qualified : 1;
+ } type;
// For function pointers of all kinds
mutable void (*func_ptr)();
@@ -107,6 +116,14 @@ namespace boost {
void* obj_ptr;
} bound_memfunc_ptr;
+ // For references to function objects. We explicitly keep
+ // track of the cv-qualifiers on the object referenced.
+ struct obj_ref_t {
+ mutable void* obj_ptr;
+ bool is_const : 1;
+ bool is_volatile : 1;
+ } obj_ref;
+
// To relax aliasing constraints
mutable char data;
};
@@ -180,34 +197,40 @@ namespace boost {
{
switch (op) {
case clone_functor_tag:
- out_buffer.obj_ptr = in_buffer.obj_ptr;
+ out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
return;
case move_functor_tag:
- out_buffer.obj_ptr = in_buffer.obj_ptr;
- in_buffer.obj_ptr = 0;
+ out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
+ in_buffer.obj_ref.obj_ptr = 0;
return;
case destroy_functor_tag:
- out_buffer.obj_ptr = 0;
+ out_buffer.obj_ref.obj_ptr = 0;
return;
case check_functor_type_tag:
{
- // DPG TBD: Since we're only storing a pointer, it's
- // possible that the user could ask for a base class or
- // derived class. Is that okay?
- const BOOST_FUNCTION_STD_NS::type_info& check_type =
- *static_cast(out_buffer.const_obj_ptr);
- if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)))
- out_buffer.obj_ptr = in_buffer.obj_ptr;
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
+
+ // Check whether we have the same type. We can add
+ // cv-qualifiers, but we can't take them away.
+ if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
+ && (!in_buffer.obj_ref.is_const
+ || out_buffer.type.const_qualified)
+ && (!in_buffer.obj_ref.is_volatile
+ || out_buffer.type.volatile_qualified))
+ out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
else
out_buffer.obj_ptr = 0;
}
return;
case get_functor_type_tag:
- out_buffer.const_obj_ptr = &typeid(F);
+ out_buffer.type.type = &typeid(F);
+ out_buffer.type.const_qualified = in_buffer.obj_ref.is_const;
+ out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile;
return;
}
}
@@ -258,13 +281,17 @@ namespace boost {
in_buffer.func_ptr = 0;
} else if (op == destroy_functor_tag)
out_buffer.func_ptr = 0;
- else /* op == check_functor_type_tag */ {
- const BOOST_FUNCTION_STD_NS::type_info& check_type =
- *static_cast(out_buffer.const_obj_ptr);
+ else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = &in_buffer.func_ptr;
else
out_buffer.obj_ptr = 0;
+ } else /* op == get_functor_type_tag */ {
+ out_buffer.type.type = &typeid(Functor);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
}
}
@@ -284,13 +311,17 @@ namespace boost {
} else if (op == destroy_functor_tag) {
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
reinterpret_cast(&out_buffer.data)->~Functor();
- } else /* op == check_functor_type_tag */ {
- const BOOST_FUNCTION_STD_NS::type_info& check_type =
- *static_cast(out_buffer.const_obj_ptr);
+ } else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = &in_buffer.data;
else
out_buffer.obj_ptr = 0;
+ } else /* op == get_functor_type_tag */ {
+ out_buffer.type.type = &typeid(Functor);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
}
}
};
@@ -339,13 +370,17 @@ namespace boost {
static_cast(out_buffer.obj_ptr);
delete f;
out_buffer.obj_ptr = 0;
- } else /* op == check_functor_type_tag */ {
- const BOOST_FUNCTION_STD_NS::type_info& check_type =
- *static_cast(out_buffer.const_obj_ptr);
+ } else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else
out_buffer.obj_ptr = 0;
+ } else /* op == get_functor_type_tag */ {
+ out_buffer.type.type = &typeid(Functor);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
}
}
@@ -370,7 +405,9 @@ namespace boost {
typedef typename get_function_tag::type tag_type;
switch (op) {
case get_functor_type_tag:
- out_buffer.const_obj_ptr = &typeid(functor_type);
+ out_buffer.type.type = &typeid(functor_type);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
return;
default:
@@ -436,13 +473,17 @@ namespace boost {
wrapper_allocator.destroy(victim);
wrapper_allocator.deallocate(victim,1);
out_buffer.obj_ptr = 0;
- } else /* op == check_functor_type_tag */ {
- const BOOST_FUNCTION_STD_NS::type_info& check_type =
- *static_cast(out_buffer.const_obj_ptr);
+ } else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else
out_buffer.obj_ptr = 0;
+ } else /* op == get_functor_type_tag */ {
+ out_buffer.type.type = &typeid(Functor);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
}
}
@@ -467,7 +508,9 @@ namespace boost {
typedef typename get_function_tag::type tag_type;
switch (op) {
case get_functor_type_tag:
- out_buffer.const_obj_ptr = &typeid(functor_type);
+ out_buffer.type.type = &typeid(functor_type);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
return;
default:
@@ -575,7 +618,7 @@ public:
detail::function::function_buffer type;
vtable->manager(functor, type, detail::function::get_functor_type_tag);
- return *static_cast(type.const_obj_ptr);
+ return *type.type.type;
}
template
@@ -584,7 +627,9 @@ public:
if (!vtable) return 0;
detail::function::function_buffer type_result;
- type_result.const_obj_ptr = &typeid(Functor);
+ type_result.type.type = &typeid(Functor);
+ type_result.type.const_qualified = is_const::value;
+ type_result.type.volatile_qualified = is_volatile::value;
vtable->manager(functor, type_result,
detail::function::check_functor_type_tag);
return static_cast(type_result.obj_ptr);
@@ -600,7 +645,9 @@ public:
if (!vtable) return 0;
detail::function::function_buffer type_result;
- type_result.const_obj_ptr = &typeid(Functor);
+ type_result.type.type = &typeid(Functor);
+ type_result.type.const_qualified = true;
+ type_result.type.volatile_qualified = is_volatile::value;
vtable->manager(functor, type_result,
detail::function::check_functor_type_tag);
// GCC 2.95.3 gets the CV qualifiers wrong here, so we
diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp
index e34ff5e..a3ee7c1 100644
--- a/include/boost/function/function_template.hpp
+++ b/include/boost/function/function_template.hpp
@@ -516,11 +516,9 @@ namespace boost {
function_buffer& functor, function_obj_ref_tag)
{
if (!boost::detail::function::has_empty_target(f.get_pointer())) {
- // DPG TBD: We might need to detect constness of
- // FunctionObj to assign into obj_ptr or const_obj_ptr to
- // be truly legit, but no platform in existence makes
- // const void* different from void*.
- functor.const_obj_ptr = f.get_pointer();
+ functor.obj_ref.obj_ptr = (void *)f.get_pointer();
+ functor.obj_ref.is_const = is_const::value;
+ functor.obj_ref.is_volatile = is_volatile::value;
return true;
} else {
return false;
diff --git a/test/contains_test.cpp b/test/contains_test.cpp
index 31963c0..fa11559 100644
--- a/test/contains_test.cpp
+++ b/test/contains_test.cpp
@@ -88,6 +88,15 @@ static void target_test()
BOOST_CHECK(!f.target());
BOOST_CHECK(f.target());
BOOST_CHECK(f.target() == &this_seventeen);
+
+ const Seventeen const_seventeen = this_seventeen;
+ f = boost::ref(const_seventeen);
+ BOOST_CHECK(!f.target());
+ BOOST_CHECK(f.target());
+ BOOST_CHECK(f.target() == &const_seventeen);
+ BOOST_CHECK(f.target());
+ BOOST_CHECK(!f.target());
+ BOOST_CHECK(!f.target());
}
static void equal_test()