3

I started experimenting with constexpr.
What I'm trying to achieve is to validate literal numeric values provided as ctor parameters.
I started with the following, throwing if constructing MyStruct with a value <= 4.

constexpr int validate(int v)
{
  return (v > 4) ? v : throw exception();
};

struct MyStruct final
{
  constexpr MyStruct(const int v)
    : _v{validate(v)}
  {
  }

  void add(int toAdd)
  {
    _v += toAdd;
  }

  int _v;
};

int main(int argc, char**)
{
  constexpr MyStruct a{500};  // ok so far...
  a.add(argc);                // ...nope 
  MyStruct b{500};            // check at runtime :(
  MyStruct c{argc};           // runtime check ok
}

Marking MyStruct as constexpr works as expected but this prevent calling add since it is not mutable.

I think this could be done since I'm targeting only literal values (known at compile time).
I'd like to avoid templates.

Stefano Azzalini
  • 1,027
  • 12
  • 21
  • Function arguments are not const expression :-/ You might pass `std::integral_constant` to allow the compile time check inside the constructor. – Jarod42 Apr 26 '17 at 16:43

1 Answers1

5

Function arguments are not const expression :-/

You might pass std::integral_constant<std::size_t, 4u> to allow the compile time check inside the constructor:

struct MyStruct final
{
    // For runtime or constexpr usage.
    constexpr MyStruct(int v) : _v{validate(v)} {}

    // For compile-time values
    template <std::size_t N>
    constexpr MyStruct(std::integral_constant<std::size_t, N>) : _v{N}
    {
        static_assert(N > 4, "Unexpected");
    }

    // ...
};

and then

MyStruct b{std::integral_constant<std::size_t, 500>{}};
Jarod42
  • 203,559
  • 14
  • 181
  • 302