1

I would like to define a string (char array) of ASCII blanks exactly as long as some static const int or macro. I want it to happen at compile time, not run time.

For example, if

static const int numBlanks = 5

then

char foo[] = "     " 

(five blanks)

and if

numBlanks = 3 

then

char foo[] = "   " 

(three blanks)

and so forth. (Why? I want to use it with strstr() to locate a sequence of at least numBlanks, with numBlanks setable at compile time.)

Yes, you do it with new, memset() and a /0, but I want to do it once at compile time, not again and again at run time.

Yes, I could come pretty close with

char foo[] = "                        "; 
foo[numBlanks] = '\0'; 

and a comment or assert() to make sure numBlanks was never greater than the compiled length of foo.

But can I do this all at compile time? Define a char array of all blanks exactly numBlanks long, where numBlanks is a C++ static const int or a macro?

Barmar
  • 741,623
  • 53
  • 500
  • 612
Charles
  • 479
  • 1
  • 3
  • 13
  • Could you use a configure script to create a header file that defines the variable with the desired length? – Barmar Mar 02 '17 at 00:45
  • Thanks @Barmar for doing the code edit. Also, I failed to mention that numBlanks would always be fairly small, say in the range 2 to 10. Yes, I guess I could but I don't know that it is worth that much effort and complexity. – Charles Mar 02 '17 at 00:51
  • You can use the C preprocessor. See http://stackoverflow.com/questions/8551418/c-preprocessor-macro-for-returning-a-string-repeated-a-certain-number-of-times – szym Mar 02 '17 at 00:55

3 Answers3

1

Here's a way to do it using variadic templates and std::make_index_sequence:

#include <utility>

template<typename T> struct blank_array;
template<std::size_t... Is>
struct blank_array<std::integer_sequence<std::size_t, Is...>> {
    static constexpr char arr[] = {(Is, ' ')..., '\0'};
};
template<std::size_t... Is>
constexpr char blank_array<std::integer_sequence<std::size_t, Is...>>::arr[];

template<std::size_t N>
constexpr const char (&blanks)[N+1] =
    blank_array<std::make_index_sequence<N>>::arr;

Example usage:

#include <iostream>

int main()
{
    std::cout << "[" << blanks<5> << "]\n";
}
aschepler
  • 70,891
  • 9
  • 107
  • 161
1

I figured out with some experimentation you can do this in c++14 or above using the more powerful constexpr statements. In this case using a recursive template.

#include <cstdio>
#include <array>

template<size_t arrsize, size_t setnum>
constexpr void initVal(std::array<char, arrsize> &tmp) {
   std::get<setnum>(tmp) = ' ';
   if (setnum) initVal<arrsize, setnum ? setnum - 1 : 0>(tmp);
}

template<size_t arrsize>
constexpr auto initArray() -> std::array<char, arrsize> {
   std::array<char, arrsize> tmp{};
   std::get<arrsize - 1>(tmp) = '\0';
   initVal<arrsize, arrsize - 2>(tmp);
   return tmp;
}

constexpr std::array<char, 5 + 1> globalArr = initArray<5 + 1>();

int main()
{
   puts(globalArr.data());
}
Vality
  • 6,577
  • 3
  • 27
  • 48
0

Thanks all. I upvoted and marked as answers several of your replies.

I guess I was hoping for something simpler. This is not the most important programming requirement in the world; I just thought perhaps I was missing a straightforward way of doing this. Your answers are great!

I decided the simplest thing was to reverse the problem: have the coder specify a string of the desired length and derive the length from that:

// Fill the following blanks array to a length equal to the minimum number of blanks to find (minimum 2)
//                            12345678901234567890
static const char blanks[] = "     ";
static const int numBlanks = sizeof(blanks)-1;
Charles
  • 479
  • 1
  • 3
  • 13