简体   繁体   中英

Comparing string-like types in template function

I want to write a functor, that compares a string-like type to another. One side of the comparison is set once at initialization and reused.

The types I want to support in any case are std::basic_string , std::basic_string_view and char* , but other like std::byte* as well as std::array and std::vector are interesting, too.

My first implementation looks like this:

template<typename StringType>
class StrcmpAlgorithm {

    StringType pattern;

  public:
    StrcmpAlgorithm(const StringType& p) : pattern(p) {}

    template<typename InputString>
    bool operator()(const InputString& input)
    {
        return input == pattern;
    }
};

However, this solution is quite limited, as the usage of the equals operator limits the types I can use and might even do the wrong thing (for example when comparing with a C string).

I'm not really sure how I should approach this. Provide multiple overloads for the call operator? Use constexpr-if and check for the type?

Essentially, having the lhs of the comparison a template parameter ( StringType ) and the rhs a different template parameter ( InputString ) leads to a combinatorical problem, even if the STL already provides some of all possible comparions. Eliminating one of those would make the whole thing much easier. But for the pattern member, I need at least the possibility to store strings with different character widths, as well as having the choice between a value and a reference type.

I believe the generally best approach is template specialization, meaning that the template class will behave differently on char*, std::array, etc.

Note, that if you have std::basic_string_view , then you can convert all of the types you mentioned to a string view, and thus use the built-in comparison function. So in your case I would implement it a bit different:

template<typename T>
std::string_view toStringView(const T& object)
{
    // covers containers (std::string_view, std::array, std::vector, std::string)
    return std::string_view(object.data(), object.size());
}

template<typename T>
std::string_view toStringView(const T* ptr)
{
    // Pointer, in this case you would need a null-terminator string.
    return std::string_view(reinterpret_cast<const char*>(ptr));
}

template<typename StringType>
class StrcmpAlgorithm {

    StringType pattern;

  public:
    StrcmpAlgorithm(StringType p) : pattern(std::move(p)) {}

    template<typename InputString>
    bool operator()(const InputString& input)
    {
        return toStringView(input) == toStringView(pattern);
    }
};

Of course, this example can and should be improved to support std::wstring_view and to fail on incompatible types (such as char** ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM