Boost logo

Boost Users :

From: Ovanes Markarian (om_boost_at_[hidden])
Date: 2008-06-16 03:09:10


Mark,

in this case template deduction does not work (or works a bit different as
assumed).

This one should work:
(std::tr1::bind(f, _1))(static_cast<const char*>(NULL));

NULL is a Macro which is defined as integral 0 and compiler can't just
convert any integer to a char const* implicitly. You should specify this
explicitly.

NullPlaceholder works, because it makes the cast in operator() for you.

Greetings,
Ovanes

On Mon, Jun 16, 2008 at 5:33 AM, Marc Horowitz <marc_at_[hidden]> wrote:

> I am attempting to use Boost.Bind to create a callable where some of
> the bound arguments might be NULL. Here is a simple example:
>
> void f(const char *) {}
>
> int main()
> {
> (std::tr1::bind(f, _1))(NULL);
>
> return(0);
> }
>
> msvc complains:
>
> c:\Program Files\boost\boost_1_35_0\boost/bind.hpp(232) : error C2664:
> 'void (const char *)' : cannot convert parameter 1 from 'const int' to
> 'const char *'
> Conversion from integral type to pointer type requires
> reinterpret_cast, C-style cast or function-style cast
> c:\Program
> Files\boost\boost_1_35_0\boost/bind/bind_template.hpp(47) : see reference to
> function template instantiation 'void boost::_bi::list1<A1>::operator
> ()<void(__cdecl *)(const char *),boost::_bi::list1<const int
> &>>(boost::_bi::type<T>,F &,A &,int)' being compiled
> with
> [
> A1=boost::arg<1>,
> T=void,
> F=void (__cdecl *)(const char *),
> A=boost::_bi::list1<const int &>
> ]
> foo.cc(20) : see reference to function template instantiation
> 'void boost::_bi::bind_t<R,F,L>::operator ()<int>(const A1 &)' being
> compiled
> with
> [
> R=void,
> F=void (__cdecl *)(const char *),
> L=boost::_bi::list1<boost::arg<1>>,
> A1=int
> ]
>
> g++ complains similarly:
>
> /usr/local/boost_1_35_0/boost/bind.hpp: In member function `void
> boost::_bi::list1<A1>::operator()(boost::_bi::type<void>, F&, A&, int) [with
> F = void (*)(const char*), A = boost::_bi::list1<const int&>, A1 =
> boost::arg<1> (*)()]':
> /usr/local/boost_1_35_0/boost/bind/bind_template.hpp:47: instantiated
> from `typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R,
> F, L>::operator()(const A1&) [with A1 = int, R = void, F = void (*)(const
> char*), L = boost::_bi::list1<boost::arg<1> (*)()>]'
> foo.cc:20: instantiated from here
> /usr/local/boost_1_35_0/boost/bind.hpp:232: error: invalid conversion
> from `const int' to `const char*'
>
> Of course, f(NULL) works just fine.
>
> The problem seems to be that NULL expands to 0. As a literal
> constant, this is assignable to any pointer, but once all the template
> stuff happens, you end up with an expression with integer type, and
> that's different. Similarly (and more predictably), this fails, too:
>
> int z = 0;
> f(z);
>
> I have a workaround, which is to replace the constant NULL with an
> expression which is assignable to any pointer type. Fortunately, this
> is easy in C++:
>
> class NullPlaceholder
> {
> public:
> template <class T>
> operator T*() const { return((T*)NULL); }
> };
>
> NullPlaceholder _NULL;
>
> Now, I can write (std::tr1::bind(f, _1))(_NULL); and the compiler is
> happy.
>
> Is there a better workaround for this problem? It seems like wanting
> to use NULL as a constant would be a pretty common case. Ideally,
> bind would be fixed so that NULL works, but I'm not sure how to do
> that without loosening the type checking for all int->pointer
> conversions. (I played around with trying to use specialization to
> add some scaffolding so that the A{1,2,3,...} template types for an
> int 0 literal would actually use a NullPlaceholder, but I didn't get
> very far, and while this would work for the compilers I use, it would
> not be formally portable.) A documentation note, at least, would have
> helped me figure out what was going wrong. Providing _NULL as a
> "placeholder" in the library would be the next best thing to having
> NULL work as is.
>
> I'm not sure if there are any other common expressions in C++ which
> will run into similar issues. Integer and string literal constants
> work just fine, but I may be missing some more subtle case.
>
> Marc
>
> P.S. It occurs to me that replacing the runtime's NULL with a macro
> which expanded to a constant of type NullPlaceholder should work
> perfectly (and does in my tests). Any use of NULL in an expression
> would dtrt, and optimize to the use of a constant. But overriding the
> runtime like this just feels sketchy.
>



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net