重载T和向量<t> </t>

时间:2011-05-06 15:02:44

标签: c++

我有一个静态方法ToString(T)和一个重载ToString(vector<T>)。这适用于正常使用,但不适用于boost绑定。请参阅我的示例代码:

#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();
}

有谁知道我做错了什么?

修改
这些是我得到的编译器错误:

/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, 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: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

5 个答案:

答案 0 :(得分:3)

ToString变为仿函数并为您的向量重载operator()。然后你可以通过bind(ToString(), ....)将其传递给绑定,并且一切都会很好(如果你传递了仿函数,bind可以在内部解析模板,但如果只是一个函数指针则不能解析)。

像这样:

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();
    }
};

答案 1 :(得分:2)

那时

&ToString<int>含糊不清。您应该通过将其强制转换为所需特定函数的签名来明确解决它。请参阅此相关问题:C++ - statement cannot resolve address for overloaded function

答案 2 :(得分:1)

问题在于,当您在第二种情况下使用ToString的地址时,编译器仍然认为您的意思是第一个版本(int)而不是vector版本。然后当bind尝试检查参数/返回类型匹配时,它不同意。

您是否可以使用其他功能名称来消除歧义?您始终可以创建一个内联包装器ToString(vector),它可以调用不同名称的帮助程序,以便在您明确调用它时使用(而不是使用绑定)。

您还可以将ToString函数地址转换为正确的重载(如另一个答案中所示),但这可能是也可能不是更清晰的解决方案。

答案 3 :(得分:0)

有了这个:

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

你明确地告诉编译器使用<int>版本的ToString,即使你试图传递一个向量。试试这个:

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

答案 4 :(得分:0)

Boost bind在函数重载方面存在一些问题。 你当然可以通过函数指针绕过这个问题。

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;
}

但是既然你想使用bind,你应该考虑改变函数名。