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.