2

I am attempting to make a print function that functions like a python print function, and I am having issues with enforcing what type the variadic arguments can be, I would like them to be restricted to const char*.

Here is my code so far:

#include <tuple>
#include <iostream>
#include <utility>
#include <type_traits>


template<
  std::size_t I=0,
  typename... Args,
  typename FUNCTION
  >
constexpr void for_each(const std::tuple<Args...>& t, FUNCTION &&func)
{
  if constexpr(I < sizeof...(Args))
  {
    func(std::get<I>(t));
    for_each<I + 1>(t, std::forward<FUNCTION>(func));
  }
}

template<
  typename... Args
  >
constexpr void print(Args... args)
{
  std::tuple t(std::forward<Args>(args)...);
  for_each(t, [=](const char* str)
  {
    std::cout << str << " ";
  });
  std::cout << '\n';
}

int main(void)
{
  print("this", "is", "a", "thing");
  print("this", "is", "not", "a", "thing");
  return 0;
}

I would like the variadic template argument in the print function to only accept const char*

asmmo
  • 6,922
  • 1
  • 11
  • 25
finlay morrison
  • 225
  • 1
  • 5
  • 1
    Why would you limit yourself so? If you change `[=](const char* str)` to `[=](const auto& elem )` your lambda can work with any type that has defined `operator <<`. – NathanOliver Jul 07 '20 at 12:29
  • FYI this is already done: [fmt](https://github.com/fmtlib/fmt). – Marek R Jul 07 '20 at 12:32

2 Answers2

4

You don't need std::tuple to do that and you can restrict your function to copy const char* only using std::enable_if, as follows

#include <iostream>
#include <type_traits>


template<typename ... Args>
constexpr std::enable_if_t<std::is_same_v<std::common_type_t<Args...>,const char*>, void>
print(Args&&... args)
{
    ((std::cout << args << " "),...);
    std::cout << '\n';
}
int main( )
{
    print("this", "is", "a", "thing");
    print("this", "is", "not", "a", "thing");
    print(5, "is", "not", "a", "thing");//compile error
    return 0;
}
asmmo
  • 6,922
  • 1
  • 11
  • 25
2

If you really want to accept only const char* you can do it like this, using static_assert (if you have C++17 support):

template<typename... Args>
constexpr void print(Args... args) {
  static_assert((std::is_same_v<Args, const char*> && ...), "Your pretty error message");
  std::tuple t(std::forward<Args>(args)...);
  for_each(t, [=](const char* str)
  {
    std::cout << str << " ";
  });
  std::cout << '\n';
}
bartop
  • 9,971
  • 1
  • 23
  • 54