1

Inspired in https://stackoverflow.com/a/37413361/1734357 I wish to make a string color lookup table of a fixed and known size, so I shouldn't need to template it, but string isn't constexpr

How to go about it?

struct Colors
{
    constexpr Colors() : colors()
    {
        for (size_t i = 0; i < 256; i++)
            colors[i] = "0;" + to_string(i) + ";255";
        for (size_t i = 0; i < 256; i++)
            colors[256 + i] = "0;255;" + to_string(255 - i);
        for (size_t i = 0; i < 256; i++)
            colors[2 * 256 + i] = to_string(i) + ";255;0";
        for (size_t i = 0; i < 256; i++)
            colors[3 * 256 + i] = "255;" + to_string(255 - i) + ";0";
    }
    string colors[4*256];
};
WurmD
  • 1,231
  • 5
  • 21
  • 42

2 Answers2

2

The problem is that to_string returns std::string, and std::string is not constexpr constructable.

This issue can be solved by using Sprout constexpr library. Although you might be disappointed by the compilation time.

#include <iostream>
#include <sprout/string.hpp>
#include <sprout/array.hpp>
#include <sprout/algorithm/transform.hpp>
#include <sprout/numeric/iota.hpp>

struct colorConv {
  typedef sprout::string<20> result_type;

  constexpr result_type
  operator()(int n) const {
      return n / 256 == 0 ? "0;" + sprout::to_string(255 - n) + ";255"
      : n / 256 == 1 ? "0;255;" + sprout::to_string(2 * 255 + 1 - n)
      : n / 256 == 2 ? sprout::to_string(3 * 255 + 2 - n ) + ";255;0;"
      : "255;" + sprout::to_string(4 * 255 + 3 - n) + ";0";
  }
};

struct Colors {
private:
  typedef colorConv::result_type string;
  constexpr static auto source = sprout::iota<sprout::array<int, 256*4> >(0);

public:
  constexpr static auto colors = sprout::transform<sprout::array<string, 256*4> >(
      sprout::begin(source),
      sprout::end(source),
      colorConv()
  );
};

int main() {
  auto& a = Colors::colors;

  for (auto&& str : Colors::colors) {
    std::cout << str << std::endl;
  }

  return 0;
}
Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
Schnappi
  • 125
  • 2
  • 10
  • True but he doesn't have to use operator+ because "255;" "NUMBER" ";0" is a valid C++ expression – Schnappi Dec 18 '19 at 13:48
  • Literal concatenation and `std::string`? How does this go together? – Scheff's Cat Dec 18 '19 at 13:49
  • Yea I meant not using std::string for colors member variable. He can still use the StringBuilder from the link I posted. He will have access to length and easily construct std::string from const char * if he wants to – Schnappi Dec 18 '19 at 13:52
  • Though, the template machinery you linked might be sufficient. Scaring... ;-) – Scheff's Cat Dec 18 '19 at 13:52
2

Quite honestly, I'd do this in a Python script, generating a C++ source file (consisting of an array definition) as a pre-build step.

That way, you get the information baked into your application at compile time, and the source for the information is still code so easy to modify.

constexpr is fine but sometimes you just want to auto-generate some code.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I once called this generative programming vs. generic programming. ;-) AWK is yet another tool which is useful for preprocessing allowing source code which consists of tab-separated text files (prepared in Excel). – Scheff's Cat Dec 18 '19 at 15:45