c++c++11overloadingstl-algorithmtemplate-function

How to select the correct function overload?


What is the correct way to select the right function overload in the following case?

#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;
}

Solution

  • You can resolve the predicate ambiguity yourself by using a 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;
    }
    

    It is also important to bear in mind that the non-template will be preferred over the template function.

    Alternatively, you can cast the function pointer (but I opinion this is more cumbersome);

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

    Demo.

    Variations of the pointer cast include typing the function pointer type and then getting a local variable pointing to the required function;

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

    Demo.


    On the matter of which option is better, it depends on the complexity of the code outside the sample, their location (i.e. your code vs third party code), the volume of the ambiguous errors, the predicate itself.

    Given the simple condition as in the OP code, a lambda could contain the test itself. The lambda is very simple in this case.

    If the count is high, the using version at a higher scope (with a local variable for the pointer conversion) could be appropriate.

    If it is a "one time" issue, the static_cast would be just fine as well. Albeit the cast looks "out of place".

    Ultimately it is probably most influenced by personal preference (or guidelines if you have any that cover this situation).

    The lambda can also be combined with more modern use of auto&& and some variadic arguments list, as seen in this answer in the linked question. It is worthwhile bearing in mind that these modern techniques dovetail well. Most modern compilers also optimism out the lambda in this case as well, so there is no cost with its use (this applies to all the options here, there all just resolve the ambiguity).

    Ideally there shouldn't really be abiguity to begin with, but it happens and we need to deal with it in the most appropriate way we can in the context we find it.