如何选择正确的函数重载?

nya*_*108 4 c++ overloading stl-algorithm template-function c++11

在以下情况下选择正确的函数重载的正确方法是什么?

#include <iostream>
#include <algorithm>

/** the correct overload **/
bool predicate( const char& c )
{
    return c == '0';
}

/** the wrong overload **/
template< typename CharType >    
bool predicate( const CharType& c, int some_other_parameters )
{
    return c == '0';
}

std::string
process_string( const std::string& str )
{
    std::string result;
    std::copy_if( str.begin( ),
                  str.end( ),
                  std::back_inserter( result ),
                  predicate );

    return result;
}

int main()
{
    std::cout << process_string("AK0NNDK0ASDAS0") << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Nia*_*all 5

您可以使用 lambda 自行解决谓词歧义;

std::string
process_string( const std::string& str )
{
    std::string result;
    std::copy_if( str.begin( ),
                  str.end( ),
                  std::back_inserter( result ),
                  [](char const& c) { return predicate(c); } );
    //            ^^ use the lambda to call the correct overload

    return result;
}
Run Code Online (Sandbox Code Playgroud)

同样重要的是要记住,非模板函数比模板函数更受青睐。

或者,您可以强制转换函数指针(但我认为这更麻烦);

std::copy_if( str.begin( ),
              str.end( ),
              std::back_inserter( result ),
              static_cast<bool(*)(const char&)>(&predicate) );
Run Code Online (Sandbox Code Playgroud)

演示

指针转换的变体包括键入函数指针类型,然后获取指向所需函数的局部变量;

using predicate_t = bool(*)(const char&);
predicate_t my_predicate = &predicate;
std::copy_if( str.begin( ),
              str.end( ),
              std::back_inserter( result ),
              my_predicate );
Run Code Online (Sandbox Code Playgroud)

演示


至于哪个选项更好,它取决于样本外部代码的复杂性、它们的位置(即您的代码与第三方代码)、不明确错误的数量、谓词本身。

给定 OP 代码中的简单条件,lambda 可以包含测试本身。在这种情况下,lambda 非常简单。

如果计数较高,则using较高范围的版本(具有用于指针转换的局部变量)可能是合适的。

如果这是“一次性”问题,那static_cast也没关系。尽管演员阵容看起来“格格不入”。

最终,它可能最受个人偏好(或指南,如果您有涵盖这种情况的指南)的影响。

lambda 还可以与更现代的用法auto&&和一些可变参数列表相结合,如链接问题中的答案所示。值得注意的是,这些现代技术非常吻合。大多数现代编译器在这种情况下也对 lambda 持乐观态度,因此使用它没有任何成本(这适用于此处的所有选项,所有选项都只是解决歧义)。

理想情况下,一开始就不应该存在歧义,但它确实发生了,我们需要在我们发现它的上下文中以最合适的方式处理它。