2017-07-14 64 views
1

我有调用函数的一个问题:C++隐性/明确的模板法专业化问题

namespace Sort { 

    enum Type { 
     insertion, selection, merge 
    }; 

    template <class Elem = int, class Container = std::vector<Elem>> 
    void sort(std::shared_ptr<Container> vectorPointer, 
       std::function<bool(Elem, Elem)> comparator = std::less<Elem>(), 
       Type type = selection) { 

     switch (type) { 
      case insertion: 
       insertionSort(vectorPointer, comparator); 
      case selection: 
       selectionSort(vectorPointer, comparator); 
      case merge: 
       mergeSort(vectorPointer, comparator); 
     } 
    } 
} 

当我把它作为这样:但是如果我开始更换

std::shared_ptr<std::vector<int>> intVector; 

Sort::sort(intVector); 

一切都OK,默认参数:

Sort::sort(intVector, std::less<int>(), merge); 

我得到一个错误信息:Candidate template ignored: could not match 'function' against 'less'

更新:

我终于使它的工作 - 明确专门的函数调用似乎做的伎俩。另外,我没有提供枚举值的名称空间。

Sort::sort<int, std::vector<int>>(intVector, std::less<int>(), Sort::merge) 

谢谢你们!

+1

无关你的问题,但有你有一个共同的指向容器的特殊原因?这是相当罕见的,在许多情况下不需要。 –

+3

至于你的问题,我个人推广甚至*进一步与模板类型,并使两个第一个参数模板以及。甚至可以使函数模拟几乎所有对容器起作用的[标准算法](http://en.cppreference.com/w/cpp/algorithm)函数,并将两个迭代器作为参数而不是容器(并因此放弃整个'Container'模板参数)。例如,如何使用模板使用'std :: less',为什么不看[[std :: map]](http://en.cppreference.com/w/cpp/container/map)? –

+0

这是我用C++编写的第一批代码之一,现在我正在重构它。指针是让事情对我有用的第一件事。我知道它有多痛苦。一旦我找出为什么它不起作用,我将删除指针。 –

回答

2
template <class Elem = int, class Container = std::vector<Elem>> 
    void sort(std::shared_ptr<Container> vectorPointer, 
       std::function<bool(Elem, Elem)> comparator = std::less<Elem>(), 
       Type type = selection) 

比较器类型取决于模板参数ELEM,所以当编译器执行模板扣规则它要求呼叫者的设置值具有自变量的类型模式匹配类型。由于'less'和'function'不是同一类型,所以这个函数不是有效的匹配。

(不要混淆类型推导逻辑是相同的,与这些类型的实例打交道时所允许的转换序列。)

如果你改变你的电话看起来像这样它会工作(虽然很明显,你不想做这道菜由于可怕的用户体验):

Sort::sort(shV, std::function<bool(int, int)>(std::less<int>()), Sort::merge); 

这样,第二个参数的类型匹配模板所期待的。 上面的例子也解决了你使用'merge'枚举器的问题,它在Sort命名空间中,并且需要命名空间限定。

一个小小的改变你的签名,以作为比较的另一个模板参数,是一种可能性:

template <class Elem = int, class Container = std::vector<Elem>, 
      class Compare = std::less<Elem>> 
void sort(std::shared_ptr<Container> vectorPointer, 
     Compare comparator = Compare(), 
     Type type = selection) { 
    switch (type) { 
     // ... 
    } 
+0

非常感谢您的解释。我不知道签名不匹配。从用户角度来看,这绝对看起来更好。 –

+1

@ bartlomiej.n它还从函数调用中消除间接级别。 'std :: function' *有效*多态,并且调用'std :: function'包装的可调用(即使'std :: function :: operator()'本身不是虚拟的)也存在虚拟调用开销。通过直接将可调用对象作为参数传递给它自己的类型,这种间接性不仅被删除,而且编译器甚至可以内联可调用的调用。对于一个像'std :: less'一样简单的函数,每个比较的虚拟调用开销是不可忽略的! – cdhowie

+0

@cdhowie我稍后会实施此更改。谢谢! –

1

如果您使用的是C++ 14,则您的std::function<bool(Elem, Elem)> comparator应为 std::function<bool(const Elem&, const Elem&)>std::function<bool(auto,auto)>

+1

虽然你可以在C++ 14的lambda中使用'auto',但是'std :: function'类型的参数不能是'auto'。 – Jarod42

+0

@ Jarod42你是对的。感谢您的更正。 – LeDYoM

+0

这会改善什么?我认为按值设置参数将是最有效的方法 –