0

Arrays with bitmasks are really popular, often times they are tedious to write and they make the code less readable, I would like to generate them with a constexpr, here is my try

#include <iostream>
#include <cstdint>
#include <vector>
#include <utility>

typedef uint32_t myT;

template <typename T>
constexpr std::vector<T> vecFarm(T &&lower, T &&upper, T &&step) {
  // std::cout << lower << " " << upper << " " << step << "\n";
  std::vector<T> v;
  if (lower < upper) {
    for (T count = lower; count < upper; count += step) {
      v.push_back(count);
    };
  }
  return (v);
}

int main() {

  std::vector<myT> k(std::move(vecFarm(myT(0), ~(myT(0)), myT(256)))); //why
  // this doesn't work ?
  // std::vector<myT> k(std::move(vecFarm(myT(0), ((~(myT(0))) >> 16), myT(256))));
  // but this one works
  // let's see what we got
  for (const auto &j : k) {
    std::cout << j << " ";
  }
  std::cout << "\n";

  return (0);
}

I have used std::move, unnamed objects and a constexpr, this code compiles fine with

g++-4.8 -O3 -std=c++11 -pthread -Werror -Wall -Wextra

but it fails at runtime because of a bad_alloc, and I can see my "small" application allocating a lot of space .

Maybe the error is huge and I can't see it, but why this doesn't work ?

Why my application does the allocation at run-time ? Isn't supposed to compute everything at compile-time ? I was expecting this to maybe fail at compile-time not at run-time.

user2485710
  • 9,451
  • 13
  • 58
  • 102

1 Answers1

2

std::bad_alloc usually means it cannot allocate any more memory. Changing your code to the following will show you why:

for (T count = lower; count < upper; count += step) {
    std::cout << "count:" << count << "\n";
    std::cout << "upper:" << upper << "\n";
};

This prints the following on the first loop when I tested it:

count:0
upper:4294967295

In other words, you have a long way to go before count < upper fails and the for loop stops, especially since you are adding only 256 each time.

Also, in order for constexpr functions to be evaluated at compile time, there are certain conditions it has to fullfil. For example, its return type must be LiteralType, and your function returns std::vector, also, exactly one return statement that contains only literal values, constexpr variables and functions. and you have a compound statement. Therefore, your function cannot be evaluated at compile time.

Also, note that if you do not fullfill these conditions, the constexpr qualifier is ignored, although if you turn on -pedantic it should give you better diagnostics.

Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • 1
    It may be worth noting that if he makes the function non-template, his code won't compile at all. – sbabbi Nov 17 '13 at 07:19
  • Infact I was focusing on the range for my type `uint32_t` and I forgot that a vector needs memory too ... ; so if I would like to break the compilation if the `constexpr` qualifier is ignored what is the best way to do just that ? – user2485710 Nov 17 '13 at 07:22
  • @user2485710: [It's not possible](http://stackoverflow.com/questions/14309245/single-expression-helper-for-compile-time-enforced-constexpr-function-evaluation). – Jesse Good Nov 17 '13 at 07:30
  • @JesseGood neither type_traits or assertions ? Nothing of nothing ? – user2485710 Nov 17 '13 at 07:31
  • @user2485710: There are a few [tricks shown here](http://stackoverflow.com/questions/14294271/forcing-a-constant-expression-to-be-evaluated-during-compile-time?lq=1), if you try to use the function where a constant expression is required, it will of course fail, but nothing in general is possible (although I think there is a C++ proposal to change this). – Jesse Good Nov 17 '13 at 07:36