基于模板类型C ++

问题描述

我正在实现“ starts_with”功能,以检查字符串是否以某些前缀开头。我希望函数能够互换比较std::stringstd::string_view。我遇到的问题是当将std::string作为参数传递时,我希望它通过引用传递,而std::string_view通过值传递。

当前我有此设置:

#include <string_view>
#include <utility>

template <typename String>
struct string_type {
  using type = const String&;
};

template <>
struct string_type<std::string_view> {
  using type = const std::string_view;
};

template <typename String>
using string_type_t = typename string_type<String>::type;

template <typename String,typename Prefix>
bool string_starts_with(string_type_t<String> str,string_type_t<Prefix> pre) {
  if (pre.length() > str.length()) {
    return false;
  }

  for (auto ch = std::pair{str.begin(),pre.begin()};
       ch.second != pre.end();
       ++ch.first,++ch.second) {
    if (*ch.first != *ch.second) {
      return false;
    }
  }

  return true;
}

int main() {
  using namespace std::string_view_literals;

  return string_starts_with("hello"sv,"hel"sv) ? 0 : 1;
}

但是gcc和clang(经过测试的here)无法推断出模板参数,我必须明确指定类型string_starts_with<std::string_view,std::string_view>(...,...)

一个显而易见的解决方案是为std::string_view提供重载,但随后我需要用相同的主体(string_starts_with(std::string,std::string)string_starts_with(std::string,std::string_view)string_starts_with(std::string_view,std::string_view)string_starts_with(std::string_view,std::string))。这可能仍然是可管理的,但是如果要向API引入另一个类似字符串的对象,例如std::vector<char>std::array<char>,那将变得难以管理。

解决方法

嵌套类型别名将禁用推论。因为编译器无法猜测嵌套参数可能在哪个类中定义。您可以定义特征模板和/或使用元编程构造(enable_ifif constexprconcept/requiresstatic_assert ...)来约束模板:

template<typename > 
struct str_ref_traits: std::false_type{};
template<>
struct str_ref_traits<std::string&>: std::true_type{};
template<>
struct str_ref_traits<std::string_view>: std::true_type{};

template <typename S,typename P>
bool string_starts_with(S str,P pre) {
    static_assert(str_ref_traits<S>::value);
    static_assert(str_ref_traits<P>::value);
    if (pre.length() > str.length())
        return false;
    return std::equal(begin(pre),end(pre),begin(str));
};

当然,如注释中所述,std::string_view可以处理std::string-通过设计。但是我想提一句不能推论嵌套类型别名的一般规则。 实际上,std::type_identity的设计目标是故意用作推导禁止器。

致谢, FM。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...