Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly implement a function with variadic number of std::string_view arguments?

Desired behavior

What I basically want is to create a function like this:

void func(std::string_view... args)
{
    (std::cout << ... << args);
}

It should be able to work only with classes that are convertible to std::string_view.

Example:

int main()
{
    const char* tmp1 = "Hello ";
    const std::string tmp2 = "World";
    const std::string_view tmp3 = "!";

    func(tmp1, tmp2, tmp3, "\n");

    return 0;
}

should print: Hello World!


Accomplished behavior

So far, I got here:

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;
}

This actually works as expected, but there is still one big problem.


Problem

Only classes that are convertible to std::string_view can be used in this function and that's great.
However, even though classes are convertible, they are not converted to std::string_view!

This leads to needless copying of data(for example when std::string is passed as argument).


Question

Is there a way to force implicit conversion of variadic arguments to std::string_view?


Note

I know about std::initializer_list, but I would like to keep function call simple, without {}.

like image 696
Iskustvo Avatar asked Jan 01 '23 13:01

Iskustvo


1 Answers

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)}... );
}

or somesuch.

like image 187
Yakk - Adam Nevraumont Avatar answered Jan 21 '23 23:01

Yakk - Adam Nevraumont