0

以下代码:

$ cat test02.cpp
#include <string>
#include <numeric>
#include <cstdlib>
#include <list>
#include <iostream>

struct myadd :
    public std::binary_function
        <const std::string&,const std::string&,std::string>
{
    std::string operator () (const std::string& x,const std::string& y) const {
        return x+" "+y;
    }
};

struct mymul :
    public std::binary_function
        <const std::string&,const std::string&,std::string>
{
    std::string operator () (const std::string& x,const std::string& y) const {
        return x+y;
    }
};

std::string spliceme(
    const std::list <std::string>& list1,
    const std::list <std::string>& list2,
    const std::binary_function
        <const std::string&,const std::string&,std::string>& add,
    const std::binary_function
        <const std::string&,const std::string&,std::string>& mul
) {
    return std::inner_product(list1.cbegin(),list1.cend(),list2.cbegin(),
        std::string(""),add,mul);
}

int main() {
    std::list <std::string> list1;
        list1.emplace_back("First");
        list1.emplace_back("Second");
        list1.emplace_back("Third");
    std::list <std::string> list2;
        list2.emplace_back("Foerst");
        list2.emplace_back("Annen");
        list2.emplace_back("Tredje");

    std::string result = spliceme(list1,list2,myadd(),mymul());
    std::cout << result << std::endl;

    return EXIT_SUCCESS;
}

生成编译器错误:

g++ -std=c++0x test02.cpp -o test02
In file included from /usr/lib/gcc/i686-pc-linux-gnu/4.6.3/include/g++-v4/numeric:62:0,
                 from test02.cpp:2:
/usr/lib/gcc/i686-pc-linux-gnu/4.6.3/include/g++-v4/bits/stl_numeric.h: In function '_Tp std::inner_product(_InputIterator1, _InputIterator1, _InputIterator2, _Tp, _BinaryOperation1, _BinaryOperation2) [with _InputIterator1 = std::_List_const_iterator<std::basic_string<char> >, _InputIterator2 = std::_List_const_iterator<std::basic_string<char> >, _Tp = std::basic_string<char>, _BinaryOperation1 = myadd, _BinaryOperation2 = std::binary_function<const std::basic_string<char>&, const std::basic_string<char>&, std::basic_string<char> >]':
test02.cpp:29:101:   instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.6.3/include/g++-v4/bits/stl_numeric.h:218:2: error: no match for call to '(std::binary_function<const std::basic_string<char>&, const std::basic_string<char>&, std::basic_string<char> >) (const std::basic_string<char>&, const std::basic_string<char>&)'
make: *** [all] Error 1

问题出现在线路上:

return std::inner_product(list1.cbegin(),list1.cend(),list2.cbegin(),
    std::string(""),add,mul);

如果我直接实例化类 myadd 和 mymul :

return std::inner_product(list1.cbegin(),list1.cend(),list2.cbegin(),
    std::string(""),myadd(),mymul());

一切都编译并正确运行。我将函数 add 和 mul 传递到函数 spliceme 的方式有什么问题?

4

3 回答 3

3

要么:

std::string spliceme(
  const std::list <std::string>& list1,
  const std::list <std::string>& list2,
  const std::function<std::string(const std::string&,const std::string&)>& add,
  const std::function<std::string(const std::string&,const std::string&)>& mul
) {
  return std::inner_product(list1.cbegin(),list1.cend(),list2.cbegin(),
    std::string(""),add,mul);
}

或这个:

template<typename Add, typename Mul>
std::string spliceme(
  const std::list <std::string>& list1,
  const std::list <std::string>& list2,
  const Add& add,
  const Mul& mul
) {
  return std::inner_product(list1.cbegin(),list1.cend(),list2.cbegin(),
    std::string(""),add,mul);
}

使您的代码工作。第一个使用类型擦除函数,第二个使用template函子。第一个允许您将正文从标题中拆分出来,第二个允许改进内联。

于 2013-07-22T20:43:01.637 回答
2
std::string spliceme(
    const std::list <std::string>& list1,
    const std::list <std::string>& list2,
    const std::binary_function
        <const std::string&,const std::string&,std::string>& add,
    const std::binary_function
        <const std::string&,const std::string&,std::string>& mul
) 

应该:

std::string spliceme(
    const std::list <std::string>& list1,
    const std::list <std::string>& list2,
    const myadd& add,
    const mymul& mul
) {

因为 operator() 不是虚函数

于 2013-07-22T20:34:58.117 回答
1

std::binary_function是一个方便的模板,用于向函数对象添加三个 typedef。它从未打算用作函数签名中的基类,因为所发生的只是您的对象被切片。它在 C++11 中已被弃用,不应再使用。Yakk 对您应该做什么给出了很好的答案。如果你真的需要这些类型定义(first_argument_type,second_argument_typeresult_type),请自己添加它们。

于 2013-07-22T21:07:03.043 回答