【问题标题】:Comparing string-like types in template function比较模板函数中的类字符串类型
【发布时间】:2020-07-20 22:01:52
【问题描述】:

我想编写一个仿函数,将类似字符串的类型与另一个进行比较。比较的一侧在初始化时设置一次并重复使用。

无论如何我想支持的类型是std::basic_stringstd::basic_string_viewchar*,但其他像std::byte* 以及std::arraystd::vector 也很有趣。

我的第一个实现如下所示:

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

但是,这个解决方案非常有限,因为等于运算符的使用限制了我可以使用的类型,甚至可能做错事(例如与 C 字符串比较时)。

我不确定我应该如何处理这个问题。为呼叫操作员提供多个重载?使用 constexpr-if 并检查类型?

本质上,将比较的 lhs 设置为模板参数 (StringType) 并将 rhs 设置为不同的模板参数 (InputString) 会导致组合问题,即使 STL 已经提供了所有可能的比较。消除其中一个将使整个事情变得容易得多。但是对于pattern 成员,我至少需要能够存储具有不同字符宽度的字符串,以及在值和引用类型之间进行选择。

【问题讨论】:

    标签: c++ string templates


    【解决方案1】:

    我认为通常最好的方法是模板专业化,这意味着模板类在 char*、std::array 等上的行为会有所不同。

    注意,如果您有std::basic_string_view,那么您可以将您提到的所有类型转换为字符串视图,从而使用内置的比较功能。所以在你的情况下,我会实现它有点不同:

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

    当然,这个例子可以而且应该被改进以支持std::wstring_view并在不兼容的类型(例如char**)上失败。

    【讨论】:

    • 我想避免不必要的转换。我可以比较 std::stringstd::string_view 就好了。此外,在您的示例中,让 StringType 成为 std::string_view 之外的任何其他内容都是一种浪费。
    • 你总是可以避免转换,它只会使代码更加复杂。你可以使用std::enable_if and use decltype(std::declval(StringType)==std::string()),当 operator == 不存在时会失败,在这种情况下 toStringView 是必要的(当然,除非你想使用自己的比较算法)。
    • 您应该注意的另一件事是,从字符串构建字符串视图是一个非常便宜的操作,因为它不包括任何内存分配/复制,并且只设置一个指针和一个大小,所以如果你关注的是效率,它可能没那么糟糕。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    相关资源
    最近更新 更多