Is there a way to statically assert on indices known at compile-time and run-time assert otherwise? Example:
template <class T, int Dim>
class Foo
{
T _data[Dim];
public:
const T &operator[](int idx) const
{
static_assert(idx < Dim, "out of range"); // error C2131: expression did not evaluate to a constant
return _data[idx];
}
};
int main()
{
Foo<float, 2> foo;
foo[0];
foo[1];
foo[2]; // compiler error
for (int i=0; i<5; ++i)
{
foo[i]; // run time assert when i > 1
}
return 0;
}
You could simply throw an exception or assert. It will fail compilation in constexpr context. This only works if the condition for throwing can be evaluated in constexpr context. Note that there is a bug in some versions of gcc that prevent the throw from working.
I don't think it's possible obtain what do you want with a single function.
Even if you develop a constexpr
function, I don't think your are able to detect when is executed run-time and when executed compile time and act in a different way.
But you can develop different functions.
By example, a template get<>()
, where the template argument is the index, that can be used only with an index known at compile-time and that can perform a static_assert()
, and an at(std::size_t)
, that can receive an index computed at run time with a run time check.
En passant:
1) I suggest, as usual in STL, the use of at()
for a bound checked access and an operator[]()
for a bound unchecked access
2) and I suggest the use of an unsigned index or you have to check that the index is >= 0
.
The following is a working example
#include <iostream>
#include <stdexcept>
template <class T, std::size_t Dim>
class Foo
{
private:
T _data[Dim];
public:
T const & operator[] (std::size_t idx) const
{ return _data[idx]; }
template <std::size_t IDX>
T const & get () const
{
static_assert(IDX < Dim, "out of range");
return this->operator[](IDX);
}
T const & at (std::size_t idx) const
{
if ( idx >= Dim )
throw std::range_error("out of range");
return this->operator[](idx);
}
};
int main ()
{
Foo<float, 2U> foo;
foo.get<0U>();
foo.get<1U>();
//foo.get<2U>(); // compiler error
for ( auto i = 0U ; i < 5U ; ++i )
foo.at(i); // run time exception when i > 1
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With