[英]How to convert boost::string_view to std::string_view?
[英]How to properly implement a function with variadic number of std::string_view arguments?
我基本上想要的是創建一個這樣的函數:
void func(std::string_view... args)
{
(std::cout << ... << args);
}
它應該只能用於可轉換為std::string_view
。
例:
int main()
{
const char* tmp1 = "Hello ";
const std::string tmp2 = "World";
const std::string_view tmp3 = "!";
func(tmp1, tmp2, tmp3, "\n");
return 0;
}
應該打印: Hello World!
到目前為止,我來到這里:
template<typename... types>
using are_strings = std::conjunction<std::is_convertible<types, std::string_view>...>;
template<typename... strings, class = std::enable_if_t<are_strings<strings...>::value, void>>
void func(strings... args)
{
(std::cout << ... << args);
}
int main()
{
const char* tmp1 = "Hello ";
const std::string tmp2 = "World";
const std::string_view tmp3 = "!";
func(tmp1, tmp2, tmp3, "\n");
return 0;
}
這實際上按預期工作,但仍有一個大問題。
只有可以轉換為std::string_view
才能在這個函數中使用,這很好。
但是,即使類是可轉換的,它們也不會轉換為std::string_view
!
這導致不必要的數據復制(例如,當std::string
作為參數傳遞時)。
有沒有辦法強制將可變參數隱式轉換為std::string_view
?
我知道std::initializer_list
,但我想保持函數調用簡單,沒有{}
。
namespace impl{
template<class...SVs>
void func(SVs... svs){
static_assert( (std::is_same< SVs, std::string_view >{} && ...) );
// your code here
}
}
template<class...Ts,
std::enable_if_t< (std::is_convertible<Ts, std::string_view >{}&&...), bool > =true
>
void func( Ts&&...ts ){
return impl::func( std::string_view{std::forward<Ts>(ts)}... );
}
或者某些。
#include <string_view>
#include <utility>
template <typename>
using string_view_t = std::string_view;
template <typename... Ts>
void func_impl(string_view_t<Ts>... args)
{
(std::cout << ... << args);
}
template <typename... Ts>
auto func(Ts&&... ts)
-> decltype(func_impl<Ts...>(std::forward<Ts>(ts)...))
{
return func_impl<Ts...>(std::forward<Ts>(ts)...);
}
如果您只是想避免不必要的數據復制,請使用前向引用,然后執行顯式強制轉換(如果仍需要)。 這樣就不會復制數據但轉發(在main.cpp示例中,所有參數都作為const引用傳遞)
template <typename... strings,
class = std::enable_if_t<are_strings<strings...>::value, void>>
void func(strings&&... args) {
(std::cout << ... << std::string_view{args});
}
不完全是你問的...但是如果你可以為args...
的長度設置一個上限args...
(下面的例子中有9個)我提出了以下解決方案:一個foo<N>
結構繼承了N
func()
static接受0,1,2,...,N std::string_view
。
這樣, func()
函數接受可轉換為std::string_view
並且所有參數都轉換為std::string_view
。
這是確切的
void func(std::string_view... args)
{ (std::cout << ... << args); }
區別在於func()
函數是foo<N>
中的static
方法, args...
length存在限制,並且每個支持的長度都有一個func()
方法。
完整的例子如下。
#include <string>
#include <utility>
#include <iostream>
#include <type_traits>
template <std::size_t ... Is>
constexpr auto getIndexSequence (std::index_sequence<Is...> is)
-> decltype(is);
template <std::size_t N>
using IndSeqFrom = decltype(getIndexSequence(std::make_index_sequence<N>{}));
template <typename T, std::size_t>
struct getType
{ using type = T; };
template <typename, typename>
struct bar;
template <typename T, std::size_t ... Is>
struct bar<T, std::index_sequence<Is...>>
{
static void func (typename getType<T, Is>::type ... args)
{ (std::cout << ... << args); }
};
template <std::size_t N, typename = std::string_view,
typename = IndSeqFrom<N>>
struct foo;
template <std::size_t N, typename T, std::size_t ... Is>
struct foo<N, T, std::index_sequence<Is...>> : public bar<T, IndSeqFrom<Is>>...
{ using bar<T, IndSeqFrom<Is>>::func ...; };
int main ()
{
const char* tmp1 = "Hello ";
const std::string tmp2 = "World";
const std::string_view tmp3 = "!";
foo<10u>::func(tmp1, tmp2, tmp3, "\n");
}
使其成為兩階段制作:
template <class... Args>
std::enable_if_t<... && std::is_same<Args, std::string_view>()>
func(Args... args)
{
(std::cout << ... << args);
}
template <class... Args>
auto func(Args&&... args)
-> std::enable_if_t<... || !std::is_same<std::decay_t<Args>, std::string_view>(),
decltype(func(std::string_view(std::forward<Args>(args))...))>
{
func(std::string_view(std::forward<Args>(args))...);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.