diff --git a/include/boost/function.hpp b/include/boost/function.hpp index 78fc18d..fe04521 100644 --- a/include/boost/function.hpp +++ b/include/boost/function.hpp @@ -454,16 +454,37 @@ namespace boost { typedef function self_type; function() : base_type() {} - + +#ifdef BOOST_COMPILER_HOOKS template - function(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) : base_type(f) {} + function(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) : + base_type(f, mixin_type(), detail::function::int_value<1>()) + { + } + + private: + template + function(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, + detail::function::int_value) : + base_type(f, mixin_type(), detail::function::int_value()) + { + } + public: +#else + template + function(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) : base_type(f) {} +#endif // !BOOST_COMPILER_HOOKS function(const self_type& f) : base_type(static_cast(f)){} template self_type& operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { +#ifdef BOOST_COMPILER_HOOKS + self_type(f, detail::function::int_value<1>()).swap(*this); +#else self_type(f).swap(*this); +#endif // !BOOST_COMPILER_HOOKS return *this; } diff --git a/include/boost/function/errors.hpp b/include/boost/function/errors.hpp new file mode 100644 index 0000000..26c4161 --- /dev/null +++ b/include/boost/function/errors.hpp @@ -0,0 +1,247 @@ +// Boost.Function library + +// Copyright (C) 2001 Doug Gregor (gregod@cs.rpi.edu) +// +// Permission to copy, use, sell and distribute this software is granted +// provided this copyright notice appears in all copies. +// Permission to modify the code and to distribute modified code is granted +// provided this copyright notice appears in all copies, and a notice +// that the code was modified is included with the copyright notice. +// +// This software is provided "as is" without express or implied warranty, +// and with no claim as to its suitability for any purpose. + +// For more information, see http://www.boost.org +// Note: this header is a header template and must NOT have multiple-inclusion +// protection. + +#ifdef BOOST_COMPILER_HOOKS + +#ifndef BOOST_FUNCTION_ERRORS_HPP +# include +# include +# include +# include +#endif // BOOST_FUNCTION_ERRORS_HPP + +#define BOOST_F_BAD_ARGS \ + BOOST_PP_CAT(incompatible_args_msg,BOOST_FUNCTION_NUM_ARGS) + +#define BOOST_F_CHECK_ARGS \ + BOOST_PP_CAT(check_args,BOOST_FUNCTION_NUM_ARGS) + +#define BOOST_F_BAD_RETURN \ + BOOST_PP_CAT(incompatible_return_msg,BOOST_FUNCTION_NUM_ARGS) + +#define BOOST_F_CHECK_RETURN \ + BOOST_PP_CAT(check_return,BOOST_FUNCTION_NUM_ARGS) + +#define BOOST_F_CHECK_TARGET \ + BOOST_PP_CAT(check_target,BOOST_FUNCTION_NUM_ARGS) + +// Comma if nonzero number of arguments +#define BOOST_F_COMMA BOOST_PP_COMMA_IF(BOOST_FUNCTION_NUM_ARGS) + +#define BOOST_F_TYPE_PLACEHOLDER(I,P) \ + BOOST_PP_IF(I, ", ",) BOOST_PP_STRINGIZE(%t) + +#define BOOST_F_ARG_TYPE(I,P) \ + BOOST_PP_COMMA_IF(I) arg< type + +#define BOOST_F_CLOSE_TMPL(I, P) > + +namespace boost { + namespace detail { + namespace function { +#ifndef BOOST_FUNCTION_ERRORS_HPP + template struct truth {}; + template struct int_value {}; + + using __gnu_cxx::arg; + using __gnu_cxx::type; + using __gnu_cxx::can_instantiate; + using __gnu_cxx::error; + + template + struct pmf {}; + + template + struct constraint { + typedef pmf force; + }; + + template struct maybe_emit_error; + template struct maybe_emit_error {}; + + template + struct maybe_emit_error { + BOOST_STATIC_CONSTANT(int, junk = sizeof(Error)); + }; + + // Check the given constraint. If it is not satisfied, emit an error + // message suppressing N instantiation levels (not including the levels + // deeper than this instantiation). + template + struct check_constraint + { + // True if the constraint is met + BOOST_STATIC_CONSTANT(bool, + value = can_instantiate > + ::value); + private: + // Possibly emit an error message + typedef typename Constraint::msg error_msg; + typedef typename error_msg::args error_msg_args; + typedef error actual_error; + typedef maybe_emit_error possible_error; + BOOST_STATIC_CONSTANT(int, junk = sizeof(possible_error)); + }; + + // Help suppress redundant error messages + template struct maybe_check; + + template + struct maybe_check + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + + template + struct maybe_check + { + BOOST_STATIC_CONSTANT(bool, value = Check::value); + }; + +#endif // !BOOST_FUNCTION_ERRORS_HPP + + // Error message when the arguments are not compatible + template + struct BOOST_F_BAD_ARGS { + // Construct the argument list + typedef arg BOOST_F_COMMA BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS, BOOST_F_ARG_TYPE, x) BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS, BOOST_F_CLOSE_TMPL, x) > args; + + // The error message text + static const char* text; + }; + +#if BOOST_FUNCTION_NUM_ARGS == 0 + template + const char* BOOST_F_BAD_ARGS::text + = "objects of type '%t' cannot be invoked with no arguments"; +#else + // Construct the error message when arguments are not compatible + template + const char* BOOST_F_BAD_ARGS< + F BOOST_F_COMMA + BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS,T)> + ::text = "objects of type '%t' cannot be invoked with Boost.Function " + "argument types '(" + BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS, + BOOST_F_TYPE_PLACEHOLDER,x) + ")'"; +#endif // BOOST_FUNCTION_NUM_ARGS != 0 + + // Concept check to determine if argument types are compatible + template + struct BOOST_F_CHECK_ARGS { + typedef BOOST_F_BAD_ARGS msg; + + F f; +#define BOOST_F_ARG(I,P) T##I a##I; + BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS,BOOST_F_ARG,) +#undef BOOST_F_ARG + + void constraints() + { + f(BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS,a)); + } + }; + + // Error message when the return types are compatible + template + struct BOOST_F_BAD_RETURN { + // Arguments to format the error message + typedef arg BOOST_F_COMMA BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS, BOOST_F_ARG_TYPE, x) , arg > BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS, BOOST_F_CLOSE_TMPL, x) > args; + + // Error message text + static const char* text; + }; + +#if BOOST_FUNCTION_NUM_ARGS == 0 + template + const char* BOOST_F_BAD_RETURN::text = + "return type when invoking object of type '%t' with no arguments is " + "not convertible to Boost.Function declared return type '%t'"; +#else + // Construct the error message when return types are not compatible + template + const char* BOOST_F_BAD_RETURN< + F, R BOOST_F_COMMA + BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS,T)> + ::text = "return type when invoking object of type '%t' with argument" + " types '(" + BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS, + BOOST_F_TYPE_PLACEHOLDER,x) + ")' is not convertible to Boost.Function declared return " + "type '%t'"; +#endif // BOOST_FUNCTION_NUM_ARGS != 0 + + // Concept check to determine if return types are compatible + template + struct BOOST_F_CHECK_RETURN { + typedef BOOST_F_BAD_RETURN< + F, R BOOST_F_COMMA + BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS,T)> msg; + + F f; +#define BOOST_F_ARG(I,P) T##I a##I; + BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS,BOOST_F_ARG,) +#undef BOOST_F_ARG + + R foo() + { + return f(BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS,a)); + } + + void constraints() + { + R (BOOST_F_CHECK_RETURN::*p)() = &BOOST_F_CHECK_RETURN::foo; + } + }; + + template + struct BOOST_F_CHECK_TARGET { + typedef check_constraint,N+1> check_args; + typedef check_constraint,N+2> check_return; + + BOOST_STATIC_CONSTANT(bool, args_ok = check_args::value); + BOOST_STATIC_CONSTANT(bool, + value = + (maybe_check::value)); + }; + } // end namespace function + } // end namespace function +} // end namespace function + +#undef BOOST_F_COMMA +#undef BOOST_F_BAD_ARGS +#undef BOOST_F_CHECK_ARGS +#undef BOOST_F_BAD_RETURN +#undef BOOST_F_CHECK_RETURN +#undef BOOST_F_CHECK_TARGET +#undef BOOST_F_TYPE_PLACEHOLDER +#undef BOOST_F_ARG_TYPE +#undef BOOST_F_CLOSE_TMPL + +#endif // BOOST_COMPILER_HOOKS + +// Don't redo work done in the first inclusion +#ifndef BOOST_FUNCTION_ERRORS_HPP +# define BOOST_FUNCTION_ERRORS_HPP +#endif // BOOST_FUNCTION_ERRORS_HPP diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index fce2a94..294be56 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -25,6 +25,9 @@ # include #endif // BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP +// Include better error handling for +#include + // Type of the default allocator #ifndef BOOST_NO_STD_ALLOCATOR # define BOOST_FUNCTION_DEFAULT_ALLOCATOR std::allocator @@ -288,6 +291,16 @@ namespace boost { this->assign_to_own(f); } +#ifdef BOOST_COMPILER_HOOKS + template + BOOST_FUNCTION_FUNCTION(Functor f, const Mixin& m, + detail::function::int_value iv) : + function_base(), Mixin(m), invoker(0) + { + this->assign_to(f, iv); + } +#endif // BOOST_COMPILER_HOOKS + ~BOOST_FUNCTION_FUNCTION() { clear(); } result_type operator()(BOOST_FUNCTION_PARMS) const @@ -318,14 +331,25 @@ namespace boost { BOOST_FUNCTION_FUNCTION& operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { +#ifdef BOOST_COMPILER_HOOKS + self_type(f, static_cast(*this), + detail::function::int_value<1>()).swap(*this); +#else self_type(f, static_cast(*this)).swap(*this); +#endif // !BOOST_COMPILER_HOOKS + return *this; } template void set(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { +#ifdef BOOST_COMPILER_HOOKS + self_type(f, static_cast(*this), + detail::function::int_value<1>()).swap(*this); +#else self_type(f, static_cast(*this)).swap(*this); +#endif // !BOOST_COMPILER_HOOKS } // Assignment from another BOOST_FUNCTION_FUNCTION @@ -378,12 +402,48 @@ namespace boost { } } +#ifdef BOOST_COMPILER_HOOKS + template + void assign_to(Functor f) + { + return assign_to(f, detail::function::int_value<1>()); + } + + template + void assign_to(Functor f, detail::function::int_value) + { + typedef detail::function::BOOST_JOIN(check_target,BOOST_FUNCTION_NUM_ARGS)< + Functor, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS, + N+2> + check_target; + + enum { ok = check_target::value }; + + maybe_assign_to(f, detail::function::truth()); + } + + template + void maybe_assign_to(Functor f, detail::function::truth) + { + typedef typename detail::function::get_function_tag::type tag; + + this->assign_to(f, tag()); + } + + template + void maybe_assign_to(Functor f, detail::function::truth) + { + // Do nothing, to avoid even more error messages + } +#else template void assign_to(Functor f) { typedef typename detail::function::get_function_tag::type tag; + this->assign_to(f, tag()); } +#endif // !BOOST_COMPILER_HOOKS template void assign_to(FunctionPtr f, detail::function::function_ptr_tag)