Holden Perkins
Holden Perkins

Reputation: 107

A way to get parameter pack from tuple / array?

So, I'm attempting to mess with constexpr strings as one will do and really only have this thus far:

template<char... CS> struct text {
    static constexpr char c_str[] = {CS...};
    static constexpr int size = sizeof...(CS);

};

and so this compiles

text<'a','b','c'> t;

std::cout<< t.c_str  <<std::endl;

and outputs 'abc' as expected.

What I'm wondering is if there's a non-convoluted way to do the reverse; have a function that returns a text type with the necessary char template arguments given a char array.

Upvotes: 3

Views: 142

Answers (1)

max66
max66

Reputation: 66230

Not exactly what you asked... and a little convoluted, I suppose... but if you define a constexpr function to detect the length of a string

constexpr std::size_t strLen (char const * str, std::size_t len = 0U)
 { return *str ? strLen(++str, ++len) : len; }

and an helper struct that define the required type

template <char const *, typename>
struct foo_helper;

template <char const * Str, std::size_t ... Is>
struct foo_helper<Str, std::index_sequence<Is...>>
 { using type = text<Str[Is]...>; };

you can obtain your type passing the string to

template <char const * Str>
struct foo : public foo_helper<Str, std::make_index_sequence<strLen(Str)>>
 { };

Unfortunately you can't pass a string literal to it in this way

foo<"abc">::type

but you have to pass from a global variable

constexpr char abcVar[] = "abc";

and call foo using the global variable

foo<abcVar>::type 

This solution uses std::index_sequence and std::make_index_sequence, available only starting from C++14, but isn't too difficult to write a substitute for they in C++11.

The following is a full working example

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

template <char ... CS>
struct text
 {
   static constexpr char c_str[] = {CS...};
   static constexpr int size = sizeof...(CS);
 };

constexpr std::size_t strLen (char const * str, std::size_t len = 0U)
 { return *str ? strLen(++str, ++len) : len; }

template <char const *, typename>
struct foo_helper;

template <char const * Str, std::size_t ... Is>
struct foo_helper<Str, std::index_sequence<Is...>>
 { using type = text<Str[Is]...>; };


template <char const * Str>
struct foo : public foo_helper<Str, std::make_index_sequence<strLen(Str)>>
 { };

constexpr char abcVar[] = "abc";

int main()
 {
   static_assert(std::is_same<foo<abcVar>::type,
                              text<'a', 'b', 'c'>>{}, "!");
 }

Off Topic: I suggest to add an ending zero in c_str[]

static constexpr char c_str[] = {CS..., 0};

if you want use it as the c_str() method of std::string.

Upvotes: 2

Related Questions