Search code examples
c++c++17constexprinitializer-list

Validation of an std::initializer_list in constexpr context


I have some class that I would like to be initialized at compile time by an initializer list that needs some level of validation.

I first tried static_assert but that wouldn't compile with the error "non-constant condition for static assertion"

What is the best way to causing a build error with this?

class foo {
public:
    constexpr foo(std::initializer_list<bar> items) {
        for(auto &&i: items) {
            if(i == 12) // example validation logic
                // fail the build
        }
    }
}

constexpr foo foo_list({0,1,2,3,4,5});// should succeed
constexpr foo foo_list_bad({0,1,12,4,68});// should fail to build


Solution

  • Use a construct that cannot be used at compile time, e.g., an exception:

    constexpr foo(std::initializer_list<bar> items)
    {
        for (auto&& i : items) {
            if (i == 12) {
                throw std::invalid_argument{""}; // for example
            }
        }
    }
    

    or a false assertion if exception is disabled:

    constexpr foo(std::initializer_list<bar> items)
    {
        for (auto&& i : items) {
            assert(i != 12);
        }
    }
    

    or call a runtime function if NDEBUG is defined:

    constexpr foo(std::initializer_list<bar> items)
    {
        for (auto&& i : items) {
            if (i == 12) {
                std::cerr << "Error\n";
            }
        }
    }
    

    A diagnostic is required if runtime-only expressions are evaluated as a part of the evaluation of a constant expression.

    static_assert does not work because the argument thereto is required to be a constant expression, which arguments to constexpr functions are not.