我正在嘗試撰寫一個簡單的模板函式,它接受所有可能的 basic_string_view 但我總是得到編譯器錯誤“找不到匹配的多載函式”。
我不知道原因;呼叫者顯式轉換為 string_view 是可行的,但我想避免這種情況;還是故意變硬?
是否有防止這種情況的扣除準則?
有沒有一種簡單的方法可以將其作為模板來實作?
這里(和Godbolt上)是我嘗試過的:
#include <string_view>
#include <string>
template <typename CharT, typename Traits> void func(std::basic_string_view<CharT, Traits> value)
//template <typename CharT> void func(std::basic_string_view<CharT> value)
//void func(std::string_view value)
{}
int main() {
std::string s;
std::string_view sv(s);
char const cs[] = "";
std::string_view csv(cs);
std::wstring ws;
std::wstring_view wsv(ws);
wchar_t const wcs[] = L"";
std::wstring_view wcsv(wcs);
func(s);
func(sv);
func(cs);
func(csv);
func(ws);
func(wsv);
func(wcs);
func(wcsv);
}
以下是 msvc、clang 和 gcc 顯示的錯誤:
error C2672: 'func': no matching overloaded function foundx64 msvc v19.latest #3
error C2783: 'void func(T)': could not deduce template argument for '<unnamed-symbol>'x64 msvc v19.latest #3
error: no matching function for call to 'func'x86-64 clang (trunk) #1
error: no matching function for call to 'func(std::string&)'x86-64 gcc (trunk) #2
編輯:
Yakks c 20 答案與 Jonathans 原始字符指標支持的混合演示。
uj5u.com熱心網友回復:
basic_string_view在C 23中有一個范圍版本的CTAD,所以在C 23中,可以使用requires子句約束為良構,通過在函式體中basic_string_view{s}借用CTAD的來推斷其型別basic_string_view
#include <string_view>
template<typename StrLike>
requires requires (const StrLike& s)
{ std::basic_string_view{s}; }
void func(const StrLike& s) {
auto sv = std::basic_string_view{s};
// use sv
}
演示
uj5u.com熱心網友回復:
通過檢查傳遞給函式的引數是否是一個范圍,也可以僅使用 C 20 來做到這一點。然后可以basic_string_view使用帶迭代器的建構式多載將范圍轉換為 a。
我還添加了一個可以處理 char 指標的多載,因為它們不是范圍。
#include <string_view>
#include <string>
#include <type_traits>
#include <ranges>
template <typename CharT, typename Traits>
void func(std::basic_string_view<CharT, Traits> value) {
// ...
}
template<typename S> requires std::ranges::contiguous_range<S>
void func(const S& s) {
func(std::basic_string_view{std::ranges::begin(s), std::ranges::end(s)});
}
template<typename S> requires (!std::ranges::range<S> && requires (S s) { std::basic_string_view<std::remove_cvref_t<decltype(s[0])>>(s); })
void func(const S& s) {
func(std::basic_string_view<std::remove_cvref_t<decltype(s[0])>>(s));
}
uj5u.com熱心網友回復:
編譯器通常不可能推斷出模板引數以便轉換成功。這不是 C 模板的設計方式。
鑒于這種:
char const cs[] = "";
func(cs);
編譯器必須能夠回答
“我必須推匯出什么模板引數CharT,以便從toTraits進行適當的隱式轉換?”const char[1]std::basic_string_view<CharT,Traits>
當然它不能做到這一點,至少不能以某種方式迭代所有型別(這是無限的,可數集)。
不幸的是,沒有模板函式的推導指南。
uj5u.com熱心網友回復:
@康桓瑋的回答太棒了。但是你應該避免未命名的概念。所以:
#include <string_view>
template<typename ZLike, template<class...>class Z>
concept can_become = requires (const ZLike& s) {
{ Z{s} };
};
void func(const can_become<std::basic_string_view> auto& s) {
auto sv = std::basic_string_view{s};
// use sv
}
活生生的例子。
這也可以使用解決C 17和早期的技術:
template<class StrLike, std::enable_if_t<can_become_v<StrLike, std::basic_string_view>, bool> = true>
void func2(const StrLike& s) {
auto sv = std::basic_string_view{s};
// use sv
}
沒有概念。
還沒到c 23有std::basic_string_view一個對 SFINAE 友好的 CTAD。沒有它,您必須知道basic_string_view傳入型別可以轉換為的確切型別,然后使用該特定型別。 operator basic_string_view<X,Y>()僅當您具有要轉換為可用的特定型別時才能找到。
您可以通過創建基于范圍的建構式來解決此問題basic_string_view,并手動推斷所涉及的字符(可能還有特征)的型別。
一個純粹的c 20不支持原始字符指標的解決方案:
template<typename ZLike, template<class...>class Z>
concept can_range_become = requires (const ZLike& s) {
{ Z{std::ranges::begin(s), std::ranges::end(s)} };
};
template<typename T>
concept stringlike = can_range_become<T, std::basic_string_view> && std::ranges::contiguous_range<T>;
void func(const stringlike auto& s) {
auto sv = std::basic_string_view{std::ranges::begin(s), std::ranges::end(s)};
// use sv
}
活生生的例子。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/473698.html
上一篇:Django無法使用靜態參考在外部js檔案中加載svg檔案
下一篇:使用模板引數將函式分配給函式指標
