Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ boost function overloaded template

I cannot figure out why this segment gives unresolved overloaded function error (gcc version 4.3.4 (Debian 4.3.4-6)):

#include <algorithm>
#include <boost/function.hpp>

// this does not work
int main1()
{
    typedef boost::function<const int&(const int&, const int&)> max;
    max m(&std::max<int>);
}

// this does not work
int main2() {
    typedef boost::function2<const int&, const int&, const int&> max;
    max m(static_cast<max>(&std::max<int>));
}

can you help me, thanks

test.cpp: In function âint main()â:
test.cpp:7: error: no matching function for call to âboost::function2<const int&, const int&, const int&>::function2(<unresolved overloaded function type>)â
/usr/include/boost/function/function_template.hpp:747: note: candidates are: boost::function2<R, T1, T2>::function2(const boost::function2<R, T1, T2>&) [with R = const int&, T0 = const int&\
, T1 = const int&]
/usr/include/boost/function/function_template.hpp:739: note:                 boost::function2<R, T1, T2>::function2(boost::function2<R, T1, T2>::clear_type*) [with R = const int&, T0 = cons\
t int&, T1 = const int&]
/usr/include/boost/function/function_template.hpp:707: note:                 boost::function2<R, T1, T2>::function2() [with R = const int&, T0 = const int&, T1 = const int&]

max/min is defined as

  template<typename _Tp>
    inline const _Tp&
    max(const _Tp& __a, const _Tp& __b)
    {
      // concept requirements
      __glibcxx_function_requires(_LessThanComparableConcept<_Tp>)
      //return  __a < __b ? __b : __a;
      if (__a < __b)
        return __b;
      return __a;
    }

I have tried all sorts of template explicit instantiation but nothing seems to work. Same problem appears with g++ 4.1 but not with ICC

this works

#include <algorithm>
#include <boost/function.hpp>

namespace std_ {
    template<typename _Tp>
    inline const _Tp&
    max(const _Tp& __a, const _Tp& __b)
    {
        // concept requirements
        //return  __a < __b ? __b : __a;
        if (__a < __b)
            return __b;
        return __a;
    }
}

int main()
{
    typedef const int &T;
    typedef boost::function<T(T,T)> min_;
    //typedef const int&(*min_)(const int&, const int&);
    min_ m(::std_::max<int>);
}

and this

#include <algorithm>
#include <boost/function.hpp>

int main()
{
    //typedef const int &T;
    //typedef boost::function<T(T,T)> min_;
    typedef const int&(*min_)(const int&, const int&);
    min_ m(::std::max<int>);
}
like image 395
Anycorn Avatar asked May 18 '10 22:05

Anycorn


2 Answers

Update: this is a gcc bug that has been fixed in gcc >=4.4. bugzilla. Also, revised my answer with a reduced test case.

There are two components to this problem: the way boost::function adopts a function pointer and the gcc bug.

boost::function - There is something strange about the error message you listed in the question; there is no candidate constructor that accepts anything like a function address. Digging into the boost::function src, the relevant constructor is (leaving out the enable_if argument):

template<typename Functor>
function(Functor f) : base_type(f) {}

So boost::function doesn't help you out at all in specifying the type of a function pointer; if the function is overloaded the address must be cast to specify its type. If an overloaded function address is used, the above template can't be instantiated, and therefore the appropriate constructor doesn't show up in the error message.

gcc bug - If you look at the stl_algobase.h header again, you'll see there are two templates named max, a two param version and a one param version. This shouldn't be a problem with you code though, right? The term &max<int> should instantiate the single param version and take its address. However, that is not what happens. You can see the problem in the reduced (no header) test case:

template <class T>
const T& max(const T& x, const T& y){
   return x > y ? x : y;
}

template <class T, class C>
const T& max(const T& x, const T& y, C comp){
   return comp(x, y) ? y : x;

}

template <class R, class A0, class A1>
struct functor{
   template <class F>
   functor(F f) : f(f) {}
   R (*f)(A0, A1);
};

int main(void){
   functor<const int&, const int&, const int&> func(&max<int>);
   return 0;
}

The above code results in a unresolved overloaded function type with gcc 4.3.4. The fix is either to remove the template <class T, class C> max(...){...} definition or add a static_cast<const int& (*)(const int&, const int&)>(...) around the function address. I'm guessing the problem has to do with incorrect application of partial explicit parameter specification, which is specified by the standard. It lets you leave out trailing template parameters to do things like specify a return value type and not the argument types. That is, the compiler instantiates both template when it should only instantiate the fully specified template. Its moot speculation though, since the bug has been fixed in gcc >= 4.4.

Since one shouldn't hack at stl_algobase.h ;) , the work around Vicente suggests is the correct one, namely cast the function pointer to the desired function pointer type const int& (*)(const int&, const int&). In your code, the cast doesn't work because, as GMan points out, you are casting to a boost::function<...>, which does nothing to resolve the function pointer ambiguity.

like image 72
academicRobot Avatar answered Oct 06 '22 13:10

academicRobot


To critique the code, there's no reason to static_cast that. Consider all the cast is going to do is use the constructor of boost::function2 to make a new boost::function2, then it will be copy-constructed into m. Just construct directly into m:

#include <algorithm>
#include <boost/function.hpp>

int main()
{
    typedef boost::function2<const int&, const int&, const int&> max;
    max m(&std::max<int>);
}

Lastly, the preferred syntax of boost::function is:

#include <algorithm>
#include <boost/function.hpp>

int main()
{
    typedef boost::function<const int&(const int&, const int&)> max;
    max m(&std::max<int>);
}

The n-ary specific classes are for older compiler support.

like image 24
GManNickG Avatar answered Oct 06 '22 13:10

GManNickG