【问题标题】:Recursive generic function used as a predicate, compilation failure递归泛型函数用作谓词,编译失败
【发布时间】:2011-06-30 08:31:32
【问题描述】:

我正在编写一个函数来比较两个列表的内容。元素的顺序无关紧要,所以我在比较之前对它们进行了排序。列表可以是普通类型list<int>,也可以是列表列表list<list<int> >

这是一个完整的精简示例:

#include <list>

template <typename T>
bool lessThanInAnyOrder(T lhs, T rhs)
{
  return lhs < rhs;
}

template <typename T>
bool lessThanInAnyOrder(std::list<T> lhs, std::list<T> rhs)
{
  lhs.sort(lessThanInAnyOrder<T>);
  rhs.sort(lessThanInAnyOrder<T>);

  //Do comparisons here, but for now just:
  return false;
}

int main()
{
  std::list<int> list1;
  std::list<int> list2;
  lessThanInAnyOrder(list1, list2);
}

这在 GCC 4.3.3 中编译,但在 Visual Studio 2008 中,我调用 lhs.sort() 时会出现以下编译错误:

error C2660: 'std::list<_Ty>::sort' : function does not take 1 arguments

有什么建议吗?

【问题讨论】:

  • 使用 g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 为我完美编译
  • @Draco Ater,不能在 ideone.com/Hx5St 上编译
  • 我正在使用 Visual Studio 2008。现在用该信息更新了问题。

标签: c++ templates stl generic-programming


【解决方案1】:

首先:我想如果你想比较集合而不考虑它们的顺序,你可能会寻找std::setset_difference, set_intersection, set_union and set_symmetric_difference algorithms

您的问题

您正在尝试实现按策略排序;如果您不能简单地专门化 std::less&lt;&gt;它的存在就是为了那个确切的目的),您可以自己取消自定义策略:(code running on codepad.org)

#include <list>
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>

namespace applogic
{
    template <typename T>
    struct sort_policy
    {
        typedef std::less<T> predicate_t;
    };

    template <> struct sort_policy<std::string>
    {
        struct _Cmp { bool operator()(const std::string& a, const std::string& b) { return a.length()>b.length(); } };
        typedef _Cmp predicate_t;
    };

    template <typename C>
        void sort(C& cont)
    {
        typedef typename sort_policy<typename C::value_type>::predicate_t P;
        std::sort(cont.begin(), cont.end(), P());
    }

    template <typename T>
        void sort(std::list<T>& cont)
    {
        typedef typename sort_policy<T>::predicate_t P;
        cont.sort(P());
    }
}

template <class C>
    static void dump(const C& cont, const std::string& msg="")
{
    std::cout << msg;
    std::copy(cont.begin(), cont.end(), std::ostream_iterator<typename C::value_type>(std::cout, ", "));
    std::cout << std::endl;
}

int main()
{
    using applogic::sort;

    std::vector<int> ints;
    ints.push_back(13);
    ints.push_back(-3);
    ints.push_back(7);

    dump(ints, "before: ");
    sort(ints);
    dump(ints, "after: ");

    std::list<std::string> strings;
    strings.push_back("very very long");
    strings.push_back("tiny");
    strings.push_back("medium size");

    dump(strings, "before: ");
    sort(strings);
    dump(strings, "after: ");

    return 0;
}

【讨论】:

    【解决方案2】:

    编译失败,因为编译器无法选择重载的“lessThanInAnyOrder”函数传递给 list::sort。您必须明确指定它的类型,例如 here

    template <typename T>
    bool lessThanInAnyOrder(std::list<T> lhs, std::list<T> rhs)
    {
      bool (*comparer)(T, T) = &lessThanInAnyOrder<T>;
      lhs.sort(comparer);
      rhs.sort(comparer);
     
      //Do comparisons here, but for now just:
      return false;
    }
    

    【讨论】:

      【解决方案3】:

      使用显式类型参数将函数包装在 std::ptr_fun 中:

      lhs.sort(std::ptr_fun<T, T>(lessThanInAnyOrder<T>));
      

      【讨论】:

        【解决方案4】:

        我的猜测,对于int 类型,您可以简单地这样写:

        lhs.sort();
        rhs.sort();
        

        Demo.

        【讨论】:

        • 谢谢,但是 lhs 和 rhs 可以是 list&lt;list&lt;int&gt; &gt; 类型。在这种情况下,我需要使用lessThanInAnyOrder&lt;list&lt;int&gt; &gt; 作为谓词。
        • @knatten,我怀疑 list&lt;int&gt;.sort(compare) 可能没有定义(因为它不是必需的)。所以你可以重载lessThanInAnyOrder&lt;int&gt;。因此对于int,它将调用sort(),而对于其他人,它将调用sort(compare)
        • list&lt;int&gt;.sort(compare) 确实有效。概念验证:bool intCompare(int lhs, int rhs) { return lhs &lt; rhs; } list1.sort(intCompare);
        • 如果您想以其他顺序对整数进行排序,即使 list&lt;int&gt; 也需要它,例如最大值优先。
        猜你喜欢
        • 2011-10-08
        • 1970-01-01
        • 2016-05-28
        • 1970-01-01
        • 2018-10-09
        • 1970-01-01
        • 2020-01-05
        • 1970-01-01
        • 2011-06-15
        相关资源
        最近更新 更多