Search code examples
c++c++17constexprif-constexpr

How to return std::array of different size based on compile-time switch?


I need to create an array of static data, where the size (and data) is known at compile time, but differs between build configurations.

This is a very dumbed-down version of what I'm trying to do (Please ignore glaring bad practices in this code as it is just an example):

constexpr ProductType PRODUCT = ProductType::A;
constexpr size_t dataSize() { return PRODUCT == ProductType::A ? 3 : 4; }

constexpr std::array<int, dataSize()> createArray()
{
    if constexpr (dataSize() == 4) {
        return std::array<int, dataSize()>{1, 2, 3, 4};
    } else {
        return std::array<int, dataSize()>{1, 2, 3};
    }
}

But this code fails to compile. The first branch of the constexpr-if is still evaluated and deemed invalid:

<source>:22:54: error: too many initializers for 'std::array<int, 3>'
   22 |         return std::array<int, dataSize()>{1, 2, 3, 4};
      |                                                      ^

But reading the docs I was under the impression that the code in the non-active branch of constexpr-if can contain code that will return wrong type, so why wouldn't this work?


Solution

  • The condition you pass to if constexpr does not depend on any template parameters, so both branches are compiled.

    From cppreference

    Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive

    void f()
    {
        if constexpr(false)
        {
            int i = 0;
            int *p = i; // Error even though in discarded statement
        }
    }