簡體   English   中英

如何正確實現具有可變數量的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)...);
}

DEMO

如果您只是想避免不必要的數據復制,請使用前向引用,然后執行顯式強制轉換(如果仍需要)。 這樣就不會復制數據但轉發(在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM