【问题标题】:Passing in a functor to a functor将函子传递给函子
【发布时间】:2011-02-03 18:31:32
【问题描述】:

我正在尝试编写一个可以传递给 std::sort 的仿函数,它将根据向量中对象的比较对表示另一个对象向量的索引的向量进行排序。我不想假设向量中的对象有一个成员 operator

template <class T, class _Pr>
class SortIndexVectorObjectsHelper : public std::binary_function<ULONG, ULONG, bool>
{
    ULONG m_ulSize;
    std::vector<T> & m_aItems;
    BOOL m_bSortAscending;
    _Pr m_Comp;

public:

    SortIndexVectorObjectsHelper(std::vector<T> & aItems, _Pr Comp) : m_aItems(aItems), m_Comp(Comp), m_ulSize(0)
    {
        m_ulSize = m_aItems.size();
    }

    bool operator()( ULONG & rLeft, ULONG & rRight) 
    {
        if (rLeft < m_ulSize && rRight < m_ulSize)
        {
            T & pLeft = m_aItems[rLeft];
            T & pRight = m_aItems[rRight];

            if (pLeft && pRight)
            {
                return m_Comp(pLeft, pRight);
            }
        }
        return false;
    }


};

struct SortFooByX: public std::binary_function<CFoo,CFoo, bool>
{
    BOOL m_bSortAscending;

    SortFooByX(BOOL bSortAscending)
    {
        m_bSortAscending = bSortAscending;
    }

    bool operator()( CFoo & _Left,  CFoo & _Right) 
    {

         if (m_bSortAscending)
         {
        if (_Left.X() < _Right.X())
           return true;
         }
         else
         {
        if (_Left.X() > _Right.X()) 
                   return true;

          }

          return false;
    }


};

std::sort(aFooIndicies.begin(), aFooIndicies.end(), SortIndexVectorObjectsHelper<CFoo, std::binary_function<CFoo, CFoo, bool> >(aFoo, SortFooByX(FALSE)));

编译它给我的错误是 2 个重载都不能转换所有参数类型。

【问题讨论】:

  • 我认为是因为您的operator() 应该接收两个const T&amp; 类型的参数,而您将其设计为接收ULONG
  • _Pr 是保留标识符;不要使用它。

标签: c++


【解决方案1】:
std::sort(aFooIndicies.begin(), aFooIndicies.end(), SortIndexVectorObjectsHelper<CFoo, std::binary_function<CFoo, CFoo, bool> >(aFoo, SortFooByX(FALSE)));

SortIndexVectorObjectsHelper 中的第二个类型参数是错误的。类型应为SortFooByX,如下图:

SortIndexVectorObjectsHelper<CFoo, SortFooByX> comparer(aFoo, SortFooByX(FALSE));
std::sort(aFooIndicies.begin(), aFooIndicies.end(), comparer);

试试这个。它现在应该可以工作了。

【讨论】:

  • 我不这么认为,一个临时对象应该可以正常工作(就像在 OP 的代码中一样)。问题是常数。比较函数所需的原型必须采用 const 引用(或按值)。
  • @Mikael:更正与临时对象无关。这是关于类模板的正确type。我声明 comparer 变量只是为了便于阅读。查看 OP 代码中 SortIndexVectorObjectsHelper 的第二个 type
【解决方案2】:

比较运算符需要采用 const 引用。 const 引用不能隐式转换为非 const 引用,因此编译器说没有与参数类型匹配的有效重载。改用这个:

bool operator()( const ULONG & rLeft, const ULONG & rRight)

我建议你在另一个比较 CFoo 和 CFoo 的类中做同样的事情。当您编写一个通过引用获取参数并且不修改这些参数的值的函数时,您最好始终将引用设为 const,它会更清晰、更安全且限制更少。当它们是非常量时,你告诉全世界你希望这些参数是可修改的,而实际上它们不需要,所以你限制了函数的可能用法,在这种情况下,这就是导致问题的原因.

正如其他人也提到的,您应该小心您的命名约定。通常,您应该避免前导下划线 _,因为它们经常用于特殊保留字或关键字(双前导下划线通常用于编译器特定指令等的保留字)。最好避免它,否则,您最终可能会偶然发现非常奇怪的错误或可移植性问题。

【讨论】:

    【解决方案3】:
    template<class Lookup, class Compare>
    struct LookupCompare {
      Lookup &lookup;
      Compare cmp;
    
      LookupCompare(Lookup &lookup, Compare cmp=Compare()) : lookup (lookup), cmp (cmp) {}
    
      template<class T>
      bool operator()(T const &a, T const &b) {
        return cmp(lookup[a], lookup[b]);
      }
    };
    

    Example:

    struct Less {
      template<class T>
      bool operator()(T const &a, T const &b) {
        return std::less<T>()(a, b);
      }
    };
    
    template<class Lookup>
    LookupCompare<Lookup, Less> lookup_compare(Lookup &lookup) {
      return lookup;
    }
    template<class Lookup, class Compare>
    LookupCompare<Lookup, Compare> lookup_compare(Lookup &lookup, Compare cmp) {
      return LookupCompare<Lookup, Compare>(lookup, compare);
    }
    
    int main() {
      vector<int> lookup;
      lookup.push_back(42);
      lookup.push_back(3);
      lookup.push_back(5);
    
      vector<int> data;
      data.push_back(0);
      data.push_back(1);
      data.push_back(2);
    
      cout << data << '\n';
      sort(data.begin(), data.end(), lookup_compare(lookup));
      cout << data << '\n';
    
      return 0;
    }
    

    我不确定你为什么使用 m_ulSize,所以我把它省略了。我也大大简化了,LookupCompare 现在适合 10 SLOC。特别是,它不需要升旗,因为您可以将 std::less 换成 std​​::greater 或注入“反转”比较器。

    【讨论】:

      猜你喜欢
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      • 2020-12-30
      • 2017-12-29
      相关资源
      最近更新 更多