切换基于模板类型 C++ 的引用参数传递
Posted
技术标签:
【中文标题】切换基于模板类型 C++ 的引用参数传递【英文标题】:Toggle pass by reference parameter based on template type C++ 【发布时间】:2020-08-16 19:55:54 【问题描述】:我正在实现一个“starts_with”函数来检查一个字符串是否以某个前缀开头。我希望该函数能够互换地比较std::string
和std::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::pairstr.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)
)实现 4 个不同的函数。这可能仍然是可管理的,但如果我想将另一个类似字符串的对象(例如 std::vector<char>
或 std::array<char>
引入 API)它就会变得无法管理。
【问题讨论】:
为什么不一直使用std::string_view
参数呢?它可以从 std::string
隐式构造
正如@IgorTandetnik 所说,只需string_view
即可。这也是 STL 对 starts_with
所做的事情。
完全忘记了!我想对于其他类似字符串的对象,我可以在函数调用中构造一个string_view
。
template <typename String, typename Prefix> bool string_starts_with(const String& str, const Prefix& pre) ...
也不能为string_view
s 工作吗?为什么需要按值传递?
@TedLyngmo 我相信,由于string_view
只是一个指向开始的指针和一个大小,它可以打包到 2 个寄存器中(至少在某些 ABI 上),因此不会发生间接寻址,编译器可以更好地优化代码。
【参考方案1】:
嵌套类型别名会禁用演绎。因为编译器无法猜测嵌套参数可能定义在哪个类中。您可以定义特征模板和/或使用元编程结构(enable_if
、if constexpr
、concept/requires
、static_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));
;
当然,正如 cmets 中所述,std::string_view
可以处理 std::string
- 设计使然。但是我想提一下嵌套类型别名不能推导出的一般规则。
其实std::type_identity
的设计目标就是故意用作推理禁用器。
问候, 调频。
【讨论】:
以上是关于切换基于模板类型 C++ 的引用参数传递的主要内容,如果未能解决你的问题,请参考以下文章