0

I want to check at compile time if some string is in a list of strings. So if I use static_assert in the main, this works. But if I want to use static_assert inside a constexpr function it gives me compile errors:

Any idea on why this compile error and how to make this compile time check work?

#include <array>
#include <string_view>

class ClosedList : public std::array< std::string_view, 3>
{
public:    
    constexpr bool hasValue( std::string_view  value) const
    {
        for (auto& e : *this) {
            if (value == e) {
                return true;
            }
        }
        return false;
    }

    constexpr std::string_view value(std::string_view value) const
    {
        static_assert( hasValue( value ), "value not in set");
        return value;

    }
};

int main()
{
    constexpr ClosedList myList = { "red", "green", "blue" };    
    static_assert(myList.hasValue( "red" ), "value not in set" );
    auto value = myList.value("red"); // compile error
}
  • 5
    Inside of a `constexpr` functions, the parameters and `this` don't count as `constexpr`. The function doesn't have to be called on a compile-time constant. – HolyBlackCat Nov 06 '20 at 21:57
  • Possible dupe https://stackoverflow.com/questions/8626055/c11-static-assert-within-constexpr-function – cigien Nov 06 '20 at 21:57
  • This is a question&answer forum. In the spirit of this forum, please ask a question. The behavior of your compiler seems correct. Please take a [tour] and read [ask]. – KamilCuk Nov 06 '20 at 22:07
  • @HolyBlackCat hasValue() uses *this and still is constexpr, so I don't see why value() cannot use this function and still being constexpr. – Martijn Breen Nov 06 '20 at 22:08
  • @MartijnBreen: You seem to be misunderstanding what the `constexpr` modifier on a function does. It causes the compiler to attempt compile-time evaluation IN A CONSTANT CONTEXT. The compiler can always do compile-time evaluation under the as-if rule, but without `constexpr` the result cannot be used in a constant context. But as HolyBlackCat said, functions marked `constexpr` can *also* be used outside constant context, so they can't guarantee that the `static_assert` parameter is a constant expression. – Ben Voigt Nov 06 '20 at 22:18
  • thank you all for the explanations, much appreciated – Martijn Breen Nov 08 '20 at 14:43

1 Answers1

0

If you need to assert something in a constexpr method, just throw. Really. As long as the throw expression isn't actually evaluated in a constant context, it's explicitly allowed to compile and be used in constexpr functions and methods:

if (!hasValue(value)) {
    throw std::runtime_error("value not in set");
}

Then it works like you want:

constexpr ClosedList myList { "a", "b", "c" };
constexpr std::string_view b = myList.value("b"); // ok
constexpr std::string_view d = myList.value("d"); // error, not a constant expression

The compile error even points to the line with the throw so you can see the error, kind of.

Demo: https://godbolt.org/z/da36dz

parktomatomi
  • 3,851
  • 1
  • 14
  • 18