如何将“basic_string”隐式转换为推导的“basic_string_view”模板?

How to implicitly convert `basic_string` to deduced `basic_string_view` template?

我正在编写一个通用算法,它可以处理任何字符类型的字符串或字符串段——因此我决定使用 std::basic_string_viewCharT 的推导模板参数和 Traits。但是,我很快发现这不允许传递 std::basic_string 对象,因为转换运算符无法对模板推导做出贡献——因此我正在寻找可行的解决方法。

在其核心,我有一个仿函数对象,它接受某种 basic_string_view 以及 CharTTraits:

的推导模板参数
struct my_algorithm {
  template <typename CharT, typename Traits>
  auto operator()(std::basic_string_view<CharT,Traits> sv) -> void;
};

我希望能够将 some std::basic_string 的实例传递给此函数,而无需显式指定函数的模板参数:

auto s = std::basic_string<char>{"hello world"}; // some basic_string, doesn't have to be '<char>'

my_algorithm{}(s); // fails to compile

由于无法推断模板重载而产生的错误是:

<source>: In function 'void test()':
<source>:13:19: error: no match for call to '(my_algorithm) (std::__cxx11::basic_string<char>&)'
   13 |     my_algorithm{}(s);
      |     ~~~~~~~~~~~~~~^~~
<source>:7:8: note: candidate: 'template<class CharT, class Traits> void my_algorithm::operator()(std::basic_string_view<_CharT, _Traits>)'
    7 |   auto operator()(std::basic_string_view<CharT,Traits> sv) -> void{}
      |        ^~~~~~~~
<source>:7:8: note:   template argument deduction/substitution failed:
<source>:13:19: note:   'std::__cxx11::basic_string<char>' is not derived from 'std::basic_string_view<_CharT, _Traits>'
   13 |     my_algorithm{}(s);
      |     ~~~~~~~~~~~~~~^~~

Live Example

是否可以在实践中解决这个问题?理想情况下,我正在寻找类似于 statically defined 的行为。

我可以想到几个潜在的解决方法,但每个都有很大的缺点:

有没有什么方法可以实现这种转换而无需彻底重载,并且不需要用户显式创建视图?


注意: 我发现另外两个问题 听起来 相似,但它们实际上都没有涉及推导的模板类型。

  1. basic_string to basic_string_view Implicit Conversion… ughhh why?

最简单的就是让它成为一个更通用的模板

struct my_algorithm {
  template <typename StringView>
  auto operator()(StringView&& sv) -> void {
      using Traits = typename std::remove_cvref_t<StringView>::traits_type;
      using CharT = typename std::remove_cvref_t<StringView>::value_type;
      /* ... */
  }
};

如果你有其他重载,你会想要 SFINAE,这在 C++20 中会更容易,有概念

template <typename T>
concept stringlike = requires { 
  typename std::remove_cvref_t<T>::traits_type;
  typename std::remove_cvref_t<T>::value_type;
}

struct my_algorithm {
  template <stringlike StringView>
  auto operator()(StringView&& sv) -> void {
      using Traits = typename std::remove_cvref_t<StringView>::traits_type;
      using CharT = typename std::remove_cvref_t<StringView>::value_type;
      /* ... */
  }
};