سؤال

i have been working for around 4 hours tryng to find a way that this code compile:

template < char ... RHS,  unsigned int i> 
struct t { 
    static const char s[] = t<' ', char(i+'0'), RHS, i-1>::s;
}; 

template <char ... RHS > 
struct t<RHS, 0> { 
    static const char s[] = {'0', RHS, '\0'};
}; 

void main() {
    std::cout << t<5>::s; // {'0',' ','1',' ','2',' ','3',' ','4',' ','5','\0'}
}

i from another post, that i dont have the link, but this code is tryng to parser a number to char at compile time. any help why this code is not compiling? thx in advance!

هل كانت مفيدة؟

المحلول

#include <iostream>

// template parameter pack needs to at the end
template < unsigned int i, char ... RHS > 
struct t {
    // can't copy-initialize an array from another array
    constexpr static char const* s()
    { return t<i-1, ' ', char(i+'0'), RHS...>::s(); };
}; 

template <char ... RHS > 
struct t<0, RHS...> {
    // can't initialize a const array inside the class,
    // need to use `constexpr`
    constexpr static char arr[]  = {'0', RHS..., '\0'};
    constexpr static char const* s()
    { return arr; }
};

// need to define the array variable, it's ODR-used
template <char ... RHS > 
constexpr char t<0, RHS...>::arr[];

int main() {
    std::cout << t<5>::s(); // {'0',' ','1',' ','2',' ','3',' ','4',' ','5','\0'}
}

And here's a version with "minimal changes":

#include <iostream>
#include <array>

template < unsigned int i, char ... RHS > 
struct t { 
    constexpr static std::array<char, sizeof...(RHS)+2*i+2> s
        = t<i-1, ' ', char(i+'0'), RHS...>::s;
};

template < unsigned int i, char ... RHS >
constexpr std::array<char, sizeof...(RHS)+2*i+2> t<i, RHS...>::s;

template <char ... RHS > 
struct t<0, RHS...> { 
    constexpr static std::array<char, sizeof...(RHS)+2> s
        = {{'0', RHS..., '\0'}};
};

template <char ... RHS > 
constexpr std::array<char, sizeof...(RHS)+2>
t<0, RHS...>::s;

int main() {
    std::cout << t<5>::s.data();
}

Note how the array is copied into each class. The most-derived ("top-level") array is odr-used via .data(), so definition of s for the primary template is necessary. The definition of s for the specialization isn't required here.

Instead of using a static data member, you could also construct the array inside a constexpr function:

constexpr static std::array<char, sizeof...(RHS)+2> arr()
{ return {{'0', RHS..., '\0'}}; }

The drawback is that this returned array has automatic lifetime, so you can't pass its .data() to the base classes.

نصائح أخرى

Here is something similar that will create a string. For example, Stringer<7> will create the string "0 1 2 3 4 5 6 7".

template <uint32_t i>
struct Stringer
{
   string str = Stringer<i - 1>().str + " " + to_string(i);
};

template <>
struct Stringer<0>
{
   string str = "0";
};

int main(int argc, const char *argv[])
{
   cout << Stringer<7>().str << endl;
   return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top