Brian Silverman | ce4aa8d | 2018-08-04 23:36:03 -0700 | [diff] [blame^] | 1 | [/ |
| 2 | / Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. |
| 3 | / Copyright (c) 2003-2008 Peter Dimov |
| 4 | / |
| 5 | / Distributed under the Boost Software License, Version 1.0. (See |
| 6 | / accompanying file LICENSE_1_0.txt or copy at |
| 7 | / http://www.boost.org/LICENSE_1_0.txt) |
| 8 | /] |
| 9 | |
| 10 | [section:troubleshooting Troubleshooting] |
| 11 | |
| 12 | [section Incorrect number of arguments] |
| 13 | |
| 14 | In a `bind(f, a1, a2, ..., aN)` expression, the function object `f` must be |
| 15 | able to take exactly N arguments. This error is normally detected at "bind |
| 16 | time"; in other words, the compilation error is reported on the line where |
| 17 | `bind()` is invoked: |
| 18 | |
| 19 | int f(int, int); |
| 20 | |
| 21 | int main() |
| 22 | { |
| 23 | boost::bind(f, 1); // error, f takes two arguments |
| 24 | boost::bind(f, 1, 2); // OK |
| 25 | } |
| 26 | |
| 27 | A common variation of this error is to forget that member functions have an |
| 28 | implicit "this" argument: |
| 29 | |
| 30 | struct X |
| 31 | { |
| 32 | int f(int); |
| 33 | } |
| 34 | |
| 35 | int main() |
| 36 | { |
| 37 | boost::bind(&X::f, 1); // error, X::f takes two arguments |
| 38 | boost::bind(&X::f, _1, 1); // OK |
| 39 | } |
| 40 | |
| 41 | [endsect] |
| 42 | |
| 43 | [section The function object cannot be called with the specified arguments] |
| 44 | |
| 45 | As in normal function calls, the function object that is bound must be |
| 46 | compatible with the argument list. The incompatibility will usually be |
| 47 | detected by the compiler at "call time" and the result is typically an error |
| 48 | in `bind.hpp` on a line that looks like: |
| 49 | |
| 50 | return f(a[a1_], a[a2_]); |
| 51 | |
| 52 | An example of this kind of error: |
| 53 | |
| 54 | int f(int); |
| 55 | |
| 56 | int main() |
| 57 | { |
| 58 | boost::bind(f, "incompatible"); // OK so far, no call |
| 59 | boost::bind(f, "incompatible")(); // error, "incompatible" is not an int |
| 60 | boost::bind(f, _1); // OK |
| 61 | boost::bind(f, _1)("incompatible"); // error, "incompatible" is not an int |
| 62 | } |
| 63 | |
| 64 | [endsect] |
| 65 | |
| 66 | [section Accessing an argument that does not exist] |
| 67 | |
| 68 | The placeholder `_N` selects the argument at position `N` from the argument |
| 69 | list passed at "call time." Naturally, it is an error to attempt to access |
| 70 | beyond the end of this list: |
| 71 | |
| 72 | int f(int); |
| 73 | |
| 74 | int main() |
| 75 | { |
| 76 | boost::bind(f, _1); // OK |
| 77 | boost::bind(f, _1)(); // error, there is no argument number 1 |
| 78 | } |
| 79 | |
| 80 | The error is usually reported in `bind.hpp`, at a line similar to: |
| 81 | |
| 82 | return f(a[a1_]); |
| 83 | |
| 84 | When emulating `std::bind1st(f, a)`, a common mistake of this category is to |
| 85 | type `bind(f, a, _2)` instead of the correct `bind(f, a, _1)`. |
| 86 | |
| 87 | [endsect] |
| 88 | |
| 89 | [section Inappropriate use of `bind(f, ...)`] |
| 90 | |
| 91 | The `bind(f, a1, a2, ..., aN)` [link bind.faq.Q_forms form] causes automatic |
| 92 | recognition of the type of `f`. It will not work with arbitrary function |
| 93 | objects; `f` must be a function or a member function pointer. |
| 94 | |
| 95 | It is possible to use this form with function objects that define |
| 96 | `result_type`, but only on compilers that support partial specialization and |
| 97 | partial ordering. In particular, MSVC up to version 7.0 does not support this |
| 98 | syntax for function objects. |
| 99 | |
| 100 | [endsect] |
| 101 | |
| 102 | [section Inappropriate use of `bind<R>(f, ...)`] |
| 103 | |
| 104 | The `bind<R>(f, a1, a2, ..., aN)` [link bind.faq.Q_forms form] supports |
| 105 | arbitrary function objects. |
| 106 | |
| 107 | It is possible (but not recommended) to use this form with functions or member |
| 108 | function pointers, but only on compilers that support partial ordering. In |
| 109 | particular, MSVC up to version 7.0 does not fully support this syntax for |
| 110 | functions and member function pointers. |
| 111 | |
| 112 | [endsect] |
| 113 | |
| 114 | [section Binding a nonstandard function] |
| 115 | |
| 116 | By default, the `bind(f, a1, a2, ..., aN)` [link bind.faq.Q_forms form] |
| 117 | recognizes "ordinary" C++ functions and function pointers. [link |
| 118 | bind.implementation.stdcall Functions that use a different calling convention], |
| 119 | or variable-argument functions such as `std::printf`, do not work. The general |
| 120 | `bind<R>(f, a1, a2, ..., aN)` [link bind.faq.Q_forms form] works with |
| 121 | nonstandard functions. |
| 122 | |
| 123 | On some platforms, extern "C" functions, like `std::strcmp`, are not |
| 124 | recognized by the short form of `bind`. |
| 125 | |
| 126 | See also [link bind.implementation.stdcall `__stdcall` and `pascal` Support]. |
| 127 | |
| 128 | [endsect] |
| 129 | |
| 130 | [section Binding an overloaded function] |
| 131 | |
| 132 | An attempt to bind an overloaded function usually results in an error, as |
| 133 | there is no way to tell which overload was meant to be bound. This is a common |
| 134 | problem with member functions with two overloads, const and non-const, as in |
| 135 | this simplified example: |
| 136 | |
| 137 | struct X |
| 138 | { |
| 139 | int& get(); |
| 140 | int const& get() const; |
| 141 | }; |
| 142 | |
| 143 | int main() |
| 144 | { |
| 145 | boost::bind(&X::get, _1); |
| 146 | } |
| 147 | |
| 148 | The ambiguity can be resolved manually by casting the (member) function |
| 149 | pointer to the desired type: |
| 150 | |
| 151 | int main() |
| 152 | { |
| 153 | boost::bind(static_cast< int const& (X::*) () const >(&X::get), _1); |
| 154 | } |
| 155 | |
| 156 | Another, arguably more readable, alternative is to introduce a temporary |
| 157 | variable: |
| 158 | |
| 159 | int main() |
| 160 | { |
| 161 | int const& (X::*get) () const = &X::get; |
| 162 | boost::bind(get, _1); |
| 163 | } |
| 164 | |
| 165 | [endsect] |
| 166 | |
| 167 | [section Modeling STL function object concepts] |
| 168 | |
| 169 | The function objects that are produced by `bind` do not model the STL |
| 170 | [@http://www.sgi.com/tech/stl/UnaryFunction.html /Unary Function/] or |
| 171 | [@http://www.sgi.com/tech/stl/BinaryFunction.html /Binary Function/] concepts, |
| 172 | even when the function objects are unary or binary operations, because the |
| 173 | function object types are missing public typedefs `result_type` and |
| 174 | `argument_type` or `first_argument_type` and `second_argument_type`. In cases |
| 175 | where these typedefs are desirable, however, the utility function |
| 176 | `make_adaptable` can be used to adapt unary and binary function objects to |
| 177 | these concepts. This allows unary and binary function objects resulting from |
| 178 | `bind` to be combined with STL templates such as |
| 179 | [@http://en.cppreference.com/w/cpp/utility/functional/unary_negate `std::unary_negate`] |
| 180 | and [@http://en.cppreference.com/w/cpp/utility/functional/binary_negate `std::binary_negate`]. |
| 181 | |
| 182 | The `make_adaptable` function is defined in [@../../../../boost/bind/make_adaptable.hpp |
| 183 | `<boost/bind/make_adaptable.hpp>`], which must be included explicitly in |
| 184 | addition to [@../../../../boost/bind.hpp `<boost/bind.hpp>`]: |
| 185 | |
| 186 | #include <boost/bind/make_adaptable.hpp> |
| 187 | |
| 188 | template <class R, class F> ``/unspecified-type/`` make_adaptable(F f); |
| 189 | |
| 190 | template<class R, class A1, class F> ``/unspecified-unary-functional-type/`` make_adaptable(F f); |
| 191 | |
| 192 | template<class R, class A1, class A2, class F> ``/unspecified-binary-functional-type/`` make_adaptable(F f); |
| 193 | |
| 194 | template<class R, class A1, class A2, class A3, class F> ``/unspecified-ternary-functional-type/`` make_adaptable(F f); |
| 195 | |
| 196 | template<class R, class A1, class A2, class A3, class A4, class F> ``/unspecified-4-ary-functional-type/`` make_adaptable(F f); |
| 197 | |
| 198 | This example shows how to use `make_adaptable` to make a predicate for "is not a space": |
| 199 | |
| 200 | typedef char char_t; |
| 201 | std::locale loc(""); |
| 202 | const std::ctype<char_t>& ct = std::use_facet<std::ctype<char_t> >(loc); |
| 203 | |
| 204 | auto isntspace = std::not1(boost::make_adaptable<bool, char_t>(boost::bind(&std::ctype<char_t>::is, &ct, std::ctype_base::space, _1))); |
| 205 | |
| 206 | In this example, `bind` creates the "is a space" (unary) predicate. It is then |
| 207 | passed to `make_adaptable` so that a function object modeling the /Unary |
| 208 | Function/ concept can be created, serving as the argument to |
| 209 | [@http://en.cppreference.com/w/cpp/utility/functional/not1 `std::not1`]. |
| 210 | |
| 211 | [endsect] |
| 212 | |
| 213 | [section `const` in signatures] |
| 214 | |
| 215 | Some compilers, including MSVC 6.0 and Borland C++ 5.5.1, have problems with |
| 216 | the top-level `const` in function signatures: |
| 217 | |
| 218 | int f(int const); |
| 219 | |
| 220 | int main() |
| 221 | { |
| 222 | boost::bind(f, 1); // error |
| 223 | } |
| 224 | |
| 225 | Workaround: remove the `const` qualifier from the argument. |
| 226 | |
| 227 | [endsect] |
| 228 | |
| 229 | [section MSVC specific: `using boost::bind;`] |
| 230 | |
| 231 | On MSVC (up to version 7.0), when `boostbind` is brought into scope with an |
| 232 | using declaration: |
| 233 | |
| 234 | using boost::bind; |
| 235 | |
| 236 | the syntax `bind<R>(f, ...)` does not work. Workaround: either use the |
| 237 | qualified name, `boost::bind`, or use an using directive instead: |
| 238 | |
| 239 | using namespace boost; |
| 240 | |
| 241 | [endsect] |
| 242 | |
| 243 | [section MSVC specific: class templates shadow function templates] |
| 244 | |
| 245 | On MSVC (up to version 7.0), a nested class template named `bind` will shadow |
| 246 | the function template `boost::bind`, breaking the `bind<R>(f, ...)`syntax. |
| 247 | Unfortunately, some libraries contain nested class templates named `bind` |
| 248 | (ironically, such code is often an MSVC specific workaround.) |
| 249 | |
| 250 | The workaround is to use the alternative `bind(type<R>(), f, ...)` syntax. |
| 251 | |
| 252 | [endsect] |
| 253 | |
| 254 | [section MSVC specific: `...` in signatures treated as type] |
| 255 | |
| 256 | MSVC (up to version 7.0) treats the ellipsis in a variable argument function |
| 257 | (such as `std::printf`) as a type. Therefore, it will accept the (incorrect in |
| 258 | the current implementation) form: |
| 259 | |
| 260 | bind(printf, "%s\n", _1); |
| 261 | |
| 262 | and will reject the correct version: |
| 263 | |
| 264 | bind<int>(printf, "%s\n", _1); |
| 265 | |
| 266 | [endsect] |
| 267 | |
| 268 | [endsect] |