开发者

Overloading T and vector<T>

开发者 https://www.devze.com 2023-03-03 03:48 出处:网络
I have a static method ToString(T) and an overload ToString(vector<T>). This works for normal use, but not with boost bind. See my example code:

I have a static method ToString(T) and an overload ToString(vector<T>). This works for normal use, but not with boost bind. See my example code:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <sstream>
#include <vector>

class MetaData
{
public:
    template<typename T>
    static std::string ToString(T inValue)
    {
        return boost::lexical_cast<std::string>(inValue);
    }

    template<typename T>
    static std::string ToString(const std::vector<T> & inValues)
    {
        std::stringstream ss;
        for (typename std::vector<T>::size_type idx = 0; idx < inValues.size(); ++idx)
        {
            if (idx != 0)
            {
                ss << ", ";
            }
            ss << inValues[idx];
        }
        return ss.str();
    }

    int getInt() { return 42; }

    std::vector<int> getIntVector()
    {
        std::vector<int> result;
        result.push_back(1);
        result.push_back(2);
        result.push_back(3);
        return result;
    }

    void test();
};

void MetaData::test()
{
    boost::function< std::string() > foo;

    // Ok
    foo = boost::bind(&ToString<int>, boost::bind(&MetaData::getInt, this));
    std::cout << foo() << std::endl;

    // Compiler errors
    foo = boost::bind(&ToString<int>, boost::bind(&MetaData::getIntVector, this));
    std::cout << foo() << std::endl;

    // Ok
    std::cout << ToString<int>(getIntVector()) << std::endl;
}

int main()
{
    MetaData metaData;
    metaData.test();
}

Does anyone know what I'm doing wrong?

Edit

These are the compiler errors I'm getting:

/usr/include/boost/bind/bind.hpp: In member function ‘R boost::_bi::list1<A1>::operator()(boost::_bi::type<R>, F&, A&, long int) [with R = std::basic_string<char>, F = std::basic_string<char> (*)(int), A = boost::_bi::list0, A1 = boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > >]’:
/usr/include/boost/bind/bind_template.hpp:20:59:   instantiated from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()() [with R = std::basic_string<char>, F = std::basic_string<char> (*)(int), L = boost::_bi::list1<boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > > >, boost::_bi::bind_t<R, F, L>::result_type = std::basic_string<char>]’
/usr/include/boost/function/function_template.hpp:132:42:   instantiated from ‘static R boost::detail::function::function_obj_invoker0<FunctionObj, R>::invoke(boost::detail::function::function_buffer&) [with FunctionObj = boost::_bi::bind_t<std::basic_string<char>, std::basic_string<char> (*)(int), boost::_bi::list1<boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > > > >, R = std::basic_string<char>]’
/usr/include/boost/function/function_template.hpp:913:60:   instantiated from ‘void boost::function0<R>::assign_to(Functor) [with Functor = boost::_bi::bind_t<std::basic_string<char>, std::basic_string<char> (*)(int), boost::_bi::list1<boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > > > >, R = std::basic_string<char>]’
/usr/include/boost/function/function_template.hpp:722:7:   instantiated from ‘boost::function0<R>::function0(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, i开发者_运维百科nt>::type) [with Functor = boost::_bi::bind_t<std::basic_string<char>, std::basic_string<char> (*)(int), boost::_bi::list1<boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > > > >, R = std::basic_string<char>, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1064:16:   instantiated from ‘boost::function<R()>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<std::basic_string<char>, std::basic_string<char> (*)(int), boost::_bi::list1<boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > > > >, R = std::basic_string<char>, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1105:5:   instantiated from ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R()>&>::type boost::function<R()>::operator=(Functor) [with Functor = boost::_bi::bind_t<std::basic_string<char>, std::basic_string<char> (*)(int), boost::_bi::list1<boost::_bi::bind_t<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData>, boost::_bi::list1<boost::_bi::value<MetaData*> > > > >, R = std::basic_string<char>, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R()>&>::type = boost::function<std::basic_string<char>()>&]’
main.cpp:55:81:   instantiated from here
/usr/include/boost/bind/bind.hpp:243:60: error: cannot convert ‘boost::_bi::result_traits<std::vector<int>, boost::_mfi::mf0<std::vector<int>, MetaData> >::type’ to ‘int’ in argument passing
make: *** [all] Error 1


Turn ToString into a functor and overload operator() for your vector. Then you can just pass it to bind via bind(ToString(), ....) and all will be well (bind can resolve the template internally if you pass the functor, but not if you just take a function pointer).

Like this:

struct ToString
{
    template<typename T>
    std::string operator()(T inValue) const
    {
        return boost::lexical_cast<std::string>(inValue);
    }

    template<typename T>
    std::string operator()(const std::vector<T> & inValues) const
    {
        std::stringstream ss;
        for (typename std::vector<T>::size_type idx = 0; idx < inValues.size(); ++idx)
        {
            if (idx != 0)
            {
                ss << ", ";
            }
            ss << inValues[idx];
        }
        return ss.str();
    }
};


&ToString<int> is ambiguous at that point. You should resolve it explicitly by casting it to the signature of the specific function you want. See this related question: C++ - statement cannot resolve address for overloaded function


The problem is that when you take the address of ToString in the second case, the compiler still thinks you mean the first version (int) instead of the vector version. Then when the bind tries to check the parameter/return type match, it doesn't agree.

Are you able to use a different function name to disambiguate? You can always create an inline wrapper ToString(vector) that calls through to the differently named helper for use when you're explicitly calling it out (not with bind).

You can also cast the ToString function address to the correct overload (as shown in another answer) but this may or may not be a clearer solution.


With this:

foo = boost::bind(&ToString<int>, boost::bind(&MetaData::getIntVector, this));

you're explicitly telling the compiler to use the <int> version of ToString, even though you're trying to pass it a vector. Try this:

foo = boost::bind(&ToString<std::vector<int> >, boost::bind(&MetaData::getIntVector, this));


Boost bind has some problems with function overloading. You could of course by-pass the issue with function pointers.

void MetaData::test()
{
    boost::function< std::string() > foo;

    typedef std::string (*PFNToString)(int i);
    typedef std::string (*PFNToString2)(std::vector<int> const& vec);
    PFNToString pfn = &MetaData::ToString<int>;
    PFNToString2 pfn2 = &MetaData::ToString<int>;

    // Ok
    foo = boost::bind(pfn, boost::bind(&MetaData::getInt, this));
    std::cout << foo() << std::endl;

    // Compiler errors
    foo = boost::bind(pfn2, boost::bind(&MetaData::getIntVector, this));
    std::cout << foo() << std::endl;

    // Ok
    std::cout << ToString<int>(getIntVector()) << std::endl;
}

But since you want to use bind maybe you should consider changing the function name.

0

精彩评论

暂无评论...
验证码 换一张
取 消