Boost.Exception and constexpr

I was playing around with Boost.Array tonight, seeing if I could make the signatures more closely match std::array. Specifically, I wanted to add 'constexpr' to "operator [] (size_t) const" and "at (size_t) const"as proposed in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3470.html But I ran into a problem. Here are the implementations: const_reference operator[](size_type i) const { BOOST_ASSERT_MSG( i < N, "out of range" ); return elems[i]; } const_reference at(size_type i) const { rangecheck(i); return elems[i]; } static void rangecheck (size_type i) { if (i >= size()) { std::out_of_range e("array<>: index out of range"); boost::throw_exception(e); } } BOOST_ASSERT does not fit into the constexpr world at all, and neither does rangecheck. I could rewrite rangecheck so it could be constexpr, but only (I believe) by throwing the exception directly, rather than using boost::throw_exception. static void rangecheck (size_type i) { if (i >= size()) throw std::out_of_range e("array<>: index out of range"); } or even just: BOOST_CONSTEXPR const_reference at(size_type i) const { return i >= size () ? throw std::out_of_range e("array<>: index out of range") : elems[i]; } Has anyone put any effort into making Boost.Exception (and BOOST_ASSERT) work with constexpr? -- Marshall Marshall Clow Idio Software <mailto:mclow.lists@gmail.com> A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait). -- Yu Suzuki

On Wed, Jan 9, 2013 at 6:23 PM, Marshall Clow <mclow.lists@gmail.com> wrote:
Has anyone put any effort into making Boost.Exception (and BOOST_ASSERT) work with constexpr?
I don't think assert or throw are compatible with constexpr. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Le 10/01/13 07:44, Emil Dotchevski a écrit :
On Wed, Jan 9, 2013 at 6:23 PM, Marshall Clow <mclow.lists@gmail.com> wrote:
Has anyone put any effort into making Boost.Exception (and BOOST_ASSERT) work with constexpr? I don't think assert or throw are compatible with constexpr.
I don't see a problem with throw. The problem is with throw_exception. We can add a basic_throw_exception that behaves as the old throw_exception that can be made constexpr #ifdef BOOST_NO_EXCEPTIONS BOOST_CONTEXPR void basic_throw_exception( std::exception const & e ); // user defined #else inline BOOST_CONTEXPR bool basic_throw_exception_assert_compatibility( std::exception const & ) { return true; } template<class E> BOOST_ATTRIBUTE_NORETURN inline BOOST_CONTEXPR void basic_throw_exception( E const & e ) { //All boost exceptions are required to derive from std::exception, //to ensure compatibility with BOOST_NO_EXCEPTIONS. if (basic_throw_exception_assert_compatibility(e)) throw e; else throw e; } #endif so that rangecheck is constexpr static BOOST_CONTTEXPR void rangecheck (size_type i) { if (i >= size()) basic_throw_exception( std::out_of_range e("array<>: index out of range") ); } On the other side, assert is a C macro so no way to qualify it as constexpr. The best we can do instead of asserting const_reference operator[](size_type i) const { BOOST_ASSERT_MSG( i < N, "out of range" ); return elems[i]; } is to abort without providing a message when the test fail. The following macro could help #if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) # define BOOST_RETURN_IF(Test, Value) return (Val) #else # define BOOST_RETURN_IF(Test, Value) \ if (Test) return (Val); \ else abort(); #endif constexpr const_reference operator[](size_type i) { return BOOST_RETURN_IF( i < N, elems[i]); } It would be reasonable to raise an issue for c++14. I would expect that the compiler could be able to manage with assert in a different way when evaluated at compile time. Best, Vicente

Vicente J. Botet Escriba wrote:
I don't see a problem with throw. The problem is with throw_exception. We can add a basic_throw_exception that behaves as the old throw_exception that can be made constexpr ...
I don't think that this will work. According to 7.1.5, The definition of a constexpr function shall satisfy the following constraints: — it shall not be virtual (10.3); — its return type shall be a literal type; — each of its parameter types shall be a literal type; — its function-body shall be = delete, = default, or a compound-statement that contains only — null statements, — static_assert-declarations — typedef declarations and alias-declarations that do not define classes or enumerations, — using-declarations, — using-directives, — and exactly one return statement; — every constructor call and implicit conversion used in initializing the return value (6.6.3, 8.5) shall be one of those allowed in a constant expression (5.19). You can't have an "if" in a constexpr function, you can't have it return void, you can't call a non-constexpr function from a constexpr function. None of the code you've suggested would compile, as far as I can see. I've never used constexpr though, so there may be something that I'm missing. You could throw by using the ternary operator and a throw expression. But you can't have a throw_exception function. For one, its return type is void, for another, its argument is not a literal. And I don't think you can do an assert, either.

On Thu, Jan 10, 2013 at 3:11 PM, Peter Dimov <lists@pdimov.com> wrote:
Vicente J. Botet Escriba wrote:
I don't see a problem with throw. The problem is with throw_exception. We can add a basic_throw_exception that behaves as the old throw_exception that can be made constexpr
...
I don't think that this will work. According to 7.1.5,
The definition of a constexpr function shall satisfy the following constraints: — it shall not be virtual (10.3); — its return type shall be a literal type; — each of its parameter types shall be a literal type; — its function-body shall be = delete, = default, or a compound-statement that contains only — null statements, — static_assert-declarations — typedef declarations and alias-declarations that do not define classes or enumerations, — using-declarations, — using-directives, — and exactly one return statement; — every constructor call and implicit conversion used in initializing the return value (6.6.3, 8.5) shall be one of those allowed in a constant expression (5.19).
You can't have an "if" in a constexpr function, you can't have it return void, you can't call a non-constexpr function from a constexpr function. None of the code you've suggested would compile, as far as I can see. I've never used constexpr though, so there may be something that I'm missing.
You could throw by using the ternary operator and a throw expression. But you can't have a throw_exception function. For one, its return type is void, for another, its argument is not a literal. And I don't think you can do an assert, either.
I don't think that the ternary operator and a throw expression is a constant expression that can be used in a constexpr function. In 5.19/2, the throw expression is explicitly mentioned as the one that cannot make a constant expression. In fact, I cannot see how a constant expression (such as a constexpr function) can throw. An assert is typically implemented as a conditional call to a function, which is an implementation detail. We cannot guarantee this function is marked with constexpr (I would wager it's not in 99% of cases). So the problem with asserts is the same: when the failing branch is taken the expression is no longer constant and it cannot be in a constexpr function.

Andrey Semashev wrote:
I don't think that the ternary operator and a throw expression is a constant expression that can be used in a constexpr function. In 5.19/2, the throw expression is explicitly mentioned as the one that cannot make a constant expression.
I suspect that you've missed the "but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered" part. You can have a throw expression, as long as it's not evaluated.
In fact, I cannot see how a constant expression (such as a constexpr function) can throw.
A constexpr function can throw when it's called with an argument that is not a constant expression. On second thought, this perhaps does make it possible to have something assert-like in a constexpr function. constexpr const_reference operator[]( size_type i ) const { return i < size()? elems[i]: ( abort(), elems[i] ); // or // return i < size()? elems[i]: ( abort(), throw 0 ); }

On second thought, this perhaps does make it possible to have something assert-like in a constexpr function.
constexpr const_reference operator[]( size_type i ) const { return i < size()? elems[i]: ( abort(), elems[i] ); }
I asked on c++std-lib and Nikolay Ivchenkov suggested: #define CONSTEXPR_CHECKER(condition, expr, failure_handler) \ ((condition) ? expr : ((failure_handler), void(), expr)) and then CONSTEXPR_CHECKER( i < size(), elems[i], assert(i < size()) ); I think that there's no point in repeating the expression, so maybe #define BOOST_CONSTEXPR_ASSERT(cond, expr) \ ((cond)? expr: (BOOST_ASSERT(expr), expr)) constexpr const_reference operator[]( size_type i ) const { return BOOST_CONSTEXPR_ASSERT( i < size(), elems[i] ); } Similarly for _MSG. Or even #define BOOST_CONSTEXPR_ASSERT(cond, expr) \ ((cond)? expr: (BOOST_ASSERT_MSG(expr, #expr " requires " #cond), expr))

constexpr const_reference operator[]( size_type i ) const { return BOOST_CONSTEXPR_ASSERT( i < size(), elems[i] ); }
The following, more intuitive, might also work: constexpr const_reference operator[]( size_type i ) const { return BOOST_ASSERT(i < size()), elems[i]; } There was some disagreement about the comma expression, but it looks like it's allowed. Most definitions of `assert` (to which BOOST_ASSERT maps usually) should also be fine, even though this is not presently guaranteed by the standard. BOOST_ASSERT_MSG does not depend on the definition of `assert` at all, so it should also work.

On Thu, Jan 10, 2013 at 3:47 PM, Peter Dimov <lists@pdimov.com> wrote:
Andrey Semashev wrote:
I don't think that the ternary operator and a throw expression is a constant expression that can be used in a constexpr function. In 5.19/2, the throw expression is explicitly mentioned as the one that cannot make a constant expression.
I suspect that you've missed the
"but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered"
part. You can have a throw expression, as long as it's not evaluated.
That's right, I didn't miss it. But when throw is evaluated the code becomes malformed, doesn't it? Well, it probably should not compile anyway (when, e.g. at() index is out of bounds) but not because at() suddenly becomes invalid.
In fact, I cannot see how a constant expression (such as a constexpr function) can throw.
A constexpr function can throw when it's called with an argument that is not a constant expression.
I must be missing something crucial. My understanding was that constexpr functions should be evaluated at compile time, am I wrong? OTOH, I tried the following code with gcc 4.6.3 -std=gnu++0x: template< typename T, unsigned int n > struct array { constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } }; int main(int, char*[]) { array< int, 5 > arr; return arr.at(10); } and it compiled (crashing in runtime due to an uncaught exception). I'm lost.

On 10.01.2013 14:49, Andrey Semashev wrote:
I must be missing something crucial. My understanding was that constexpr functions should be evaluated at compile time, am I wrong? Yes. A constexpr function *can* be evaluated at compile time if all its arguments are constant expressions and evaluation using those arguments doesn't hit anything that isn't allowed (like a throw). If that is the case, the result itself may be used as a constant expression. Otherwise, it's a normal function call. A constexpr function only *must* be evaluated at compile time if the result has to be a constant expression. In that case, it is a compile time error if it cannot be evaluated.
Sebastian

On Thu, Jan 10, 2013 at 6:22 PM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
On 10.01.2013 14:49, Andrey Semashev wrote:
I must be missing something crucial. My understanding was that constexpr functions should be evaluated at compile time, am I wrong?
Yes. A constexpr function *can* be evaluated at compile time if all its arguments are constant expressions and evaluation using those arguments doesn't hit anything that isn't allowed (like a throw). If that is the case, the result itself may be used as a constant expression. Otherwise, it's a normal function call.
Ok, thank you for clearing this.
A constexpr function only *must* be evaluated at compile time if the result has to be a constant expression. In that case, it is a compile time error if it cannot be evaluated.
So, this means that my argument is still valid to some point. If array::at() is used in a constant expression and the check fails, the function is no longer valid. Changing my previous code sample to this: template< typename T, unsigned int n > struct array { constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } }; template< int m > struct check { static int get() { return m; } }; int main(int, char*[]) { array< int, 5 > arr; check< arr.at(10) > a; return a::get(); } produces the following error: ./constexpr_test.cpp: In function ‘int main(int, char**)’: ./constexpr_test.cpp:19:21: in constexpr expansion of ‘arr.array<T, n>::at [with T = int, unsigned int n = 5u](10u)’ ./constexpr_test.cpp:6:36: error: expression ‘<throw-expression>’ is not a constant-expression ./constexpr_test.cpp:19:23: note: in template argument for type ‘int’ ./constexpr_test.cpp:19:26: error: invalid type in declaration before ‘;’ token ./constexpr_test.cpp:20:12: error: ‘a’ is not a class, namespace, or enumeration Not exactly the error that is expected, I'd say.

template< typename T, unsigned int n > struct array { constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } };
template< int m > struct check { static int get() { return m; } };
int main(int, char*[]) { array< int, 5 > arr; check< arr.at(10) > a; return a::get(); }
produces the following error:
./constexpr_test.cpp: In function ‘int main(int, char**)’: ./constexpr_test.cpp:19:21: in constexpr expansion of ‘arr.array<T, n>::at [with T = int, unsigned int n = 5u](10u)’ ./constexpr_test.cpp:6:36: error: expression ‘<throw-expression>’ is not a constant-expression This is expected. Not ideal, but that's what you currently get from constexpr-capable compilers. Clang isn't much different. ./constexpr_test.cpp:19:26: error: invalid type in declaration before ‘;’ token This is just stupid. ./constexpr_test.cpp:20:12: error: ‘a’ is not a class, namespace, or enumeration This is your own fault. You want a.get(), not a::get(). Or maybe the
On 10.01.2013 15:46, Andrey Semashev wrote: line above was supposed to be a typedef? Sebastian

On Thu, Jan 10, 2013 at 6:53 PM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
On 10.01.2013 15:46, Andrey Semashev wrote:
./constexpr_test.cpp:20:12: error: ‘a’ is not a class, namespace, or enumeration
This is your own fault. You want a.get(), not a::get(). Or maybe the line above was supposed to be a typedef?
That was a typo, sorry.

Le 10/01/13 15:46, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 6:22 PM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
On 10.01.2013 14:49, Andrey Semashev wrote:
I must be missing something crucial. My understanding was that constexpr functions should be evaluated at compile time, am I wrong? Yes. A constexpr function *can* be evaluated at compile time if all its arguments are constant expressions and evaluation using those arguments doesn't hit anything that isn't allowed (like a throw). If that is the case, the result itself may be used as a constant expression. Otherwise, it's a normal function call. Ok, thank you for clearing this.
A constexpr function only *must* be evaluated at compile time if the result has to be a constant expression. In that case, it is a compile time error if it cannot be evaluated. So, this means that my argument is still valid to some point. If array::at() is used in a constant expression and the check fails, the function is no longer valid. Changing my previous code sample to this:
template< typename T, unsigned int n > struct array { constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } };
template< int m > struct check { static int get() { return m; } };
int main(int, char*[]) { array< int, 5 > arr; check< arr.at(10) > a; return a::get(); }
produces the following error:
./constexpr_test.cpp: In function ‘int main(int, char**)’: ./constexpr_test.cpp:19:21: in constexpr expansion of ‘arr.array<T, n>::at [with T = int, unsigned int n = 5u](10u)’ ./constexpr_test.cpp:6:36: error: expression ‘<throw-expression>’ is not a constant-expression Have you tried declaring arr as a constexpr?
Vicente

Le 10/01/13 19:13, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Have you tried declaring arr as a constexpr? It doesn't make any difference, the error is the same.
The constructor for array must be declared constexpr as well. The following works with clang 3.1, 3.2 and gcc 4.7.1, 4.7.2. I have no access to other C++11 compilers now. Could you try it? Best, Vicente // Note the comments //******** template< typename T, unsigned int n > struct array { constexpr array() {}; // *************** constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } }; template< int m > struct check { static int get() { return m; } }; int main(int, char*[]) { constexpr array< int, 5 > arr; // *************** check< arr.at(3) > a; return a.get(); // *************** }

On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 19:13, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Have you tried declaring arr as a constexpr?
It doesn't make any difference, the error is the same.
The constructor for array must be declared constexpr as well. The following works with clang 3.1, 3.2 and gcc 4.7.1, 4.7.2. I have no access to other C++11 compilers now. Could you try it?
The error is still the same. ./constexpr_test.cpp: In function ‘int main(int, char**)’: ./constexpr_test.cpp:20:21: in constexpr expansion of ‘arr.array<T, n>::at<int, 5u>(10u)’ ./constexpr_test.cpp:7:36: error: expression ‘<throw-expression>’ is not a constant-expression ./constexpr_test.cpp:20:23: note: in template argument for type ‘int’ ./constexpr_test.cpp:20:26: error: invalid type in declaration before ‘;’ token ./constexpr_test.cpp:21:14: error: request for member ‘get’ in ‘a’, which is of non-class type ‘int’ The constructor doesn't make any difference, it's the at() method body that causes the error. The disappointing part is that the error message itself does not point to the source of the problem and is misleading. The note before the error mentions the method arguments but (a) it will not necessarily be displayed by various IDEs and (b) it doesn't point out the problem (i.e. that 10 > 5). If only it was possible to overload at() based on constexpr qualification and use static_assert to display the message...

Le 10/01/13 20:12, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 19:13, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Have you tried declaring arr as a constexpr? It doesn't make any difference, the error is the same.
The constructor for array must be declared constexpr as well. The following works with clang 3.1, 3.2 and gcc 4.7.1, 4.7.2. I have no access to other C++11 compilers now. Could you try it? The error is still the same.
./constexpr_test.cpp: In function ‘int main(int, char**)’: ./constexpr_test.cpp:20:21: in constexpr expansion of ‘arr.array<T, n>::at<int, 5u>(10u)’ ./constexpr_test.cpp:7:36: error: expression ‘<throw-expression>’ is not a constant-expression ./constexpr_test.cpp:20:23: note: in template argument for type ‘int’ ./constexpr_test.cpp:20:26: error: invalid type in declaration before ‘;’ token ./constexpr_test.cpp:21:14: error: request for member ‘get’ in ‘a’, which is of non-class type ‘int’
The constructor doesn't make any difference, it's the at() method body that causes the error. Yes it does. The error you get here is the one you must obtain when the exception is throw during compile time. The disappointing part is that the error message itself does not point to the source of the problem and is misleading. The note before the error mentions the method arguments but (a) it will not necessarily be displayed by various IDEs and (b) it doesn't point out the problem (i.e. that 10 > 5). If only it was possible to overload at() based on constexpr qualification and use static_assert to display the message...
The error message is a QOI. Here it is the error with clang 3.1/3.2 clang-darwin.compile.c++ ../../../bin.v2/libs/thread/test/test_so.test/clang-darwin-3.1xl/debug/threading-multi/test_so.o ../example/test_so.cpp:20:12: error: non-type template argument is not a constant expression check< arr.at(10) > a; ^~~~~~~~~~ ../example/test_so.cpp:7:30: note: subexpression not valid in a constant expression return i < n ? T() : throw 0; ^ ../example/test_so.cpp:20:12: note: in call to '10->at()' check< arr.at(10) > a; ^ Best, Vicente

On Thu, Jan 10, 2013 at 11:31 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 20:12, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 19:13, Andrey Semashev a écrit :
The constructor doesn't make any difference, it's the at() method body that causes the error.
Yes it does.
The implicit default constructor is constexpr when possible, so defining it constexpr explicitly doesn't make any difference.
The error message is a QOI. Here it is the error with clang 3.1/3.2
clang-darwin.compile.c++ ../../../bin.v2/libs/thread/test/test_so.test/clang-darwin-3.1xl/debug/threading-multi/test_so.o ../example/test_so.cpp:20:12: error: non-type template argument is not a constant expression check< arr.at(10) > a; ^~~~~~~~~~ ../example/test_so.cpp:7:30: note: subexpression not valid in a constant expression
return i < n ? T() : throw 0; ^ ../example/test_so.cpp:20:12: note: in call to '10->at()' check< arr.at(10) > a; ^
This looks better, thanks.

Le 10/01/13 20:47, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 11:31 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 20:12, Andrey Semashev a écrit :
Le 10/01/13 19:13, Andrey Semashev a écrit : The constructor doesn't make any difference, it's the at() method body
On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote: that causes the error. Yes it does. The implicit default constructor is constexpr when possible, so defining it constexpr explicitly doesn't make any difference.
Maybe you are right. I said that because clang was requiring it but gcc-4.7 accept the default constructor as a constexpr. clang-darwin.compile.c++ ../../../bin.v2/libs/thread/test/test_so.test/clang-darwin-3.2xl/debug/threading-multi/test_so.o ../example/test_so.cpp:19:31: error: default initialization of an object of const type 'const array<int, 5>' requires a user-provided default constructor constexpr array< int, 5 > arr; ^ ../example/test_so.cpp:21:12: error: use of undeclared identifier 'a' return a.get(); Best, Vicente

Le 10/01/13 22:10, Vicente J. Botet Escriba a écrit :
Le 10/01/13 20:47, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 11:31 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 20:12, Andrey Semashev a écrit :
Le 10/01/13 19:13, Andrey Semashev a écrit : The constructor doesn't make any difference, it's the at() method body
On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote: that causes the error. Yes it does. The implicit default constructor is constexpr when possible, so defining it constexpr explicitly doesn't make any difference.
Maybe you are right. I said that because clang was requiring it but gcc-4.7 accept the default constructor as a constexpr.
I have checked it and you were right. "If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr" It seems that clang 3.2 has a bug here. Thanks, Vicente

On Jan 10, 2013, at 9:06 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/01/13 15:46, Andrey Semashev a écrit :
On Thu, Jan 10, 2013 at 6:22 PM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
On 10.01.2013 14:49, Andrey Semashev wrote:
I must be missing something crucial. My understanding was that constexpr functions should be evaluated at compile time, am I wrong? Yes. A constexpr function *can* be evaluated at compile time if all its arguments are constant expressions and evaluation using those arguments doesn't hit anything that isn't allowed (like a throw). If that is the case, the result itself may be used as a constant expression. Otherwise, it's a normal function call. Ok, thank you for clearing this.
A constexpr function only *must* be evaluated at compile time if the result has to be a constant expression. In that case, it is a compile time error if it cannot be evaluated. So, this means that my argument is still valid to some point. If array::at() is used in a constant expression and the check fails, the function is no longer valid. Changing my previous code sample to this:
template< typename T, unsigned int n > struct array { constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } };
template< int m > struct check { static int get() { return m; } };
int main(int, char*[]) { array< int, 5 > arr; check< arr.at(10) > a; return a::get(); }
produces the following error:
./constexpr_test.cpp: In function ‘int main(int, char**)’: ./constexpr_test.cpp:19:21: in constexpr expansion of ‘arr.array<T, n>::at [with T = int, unsigned int n = 5u](10u)’ ./constexpr_test.cpp:6:36: error: expression ‘<throw-expression>’ is not a constant-expression Have you tried declaring arr as a constexpr?
Here's my test case (using a locally modified Boost::Array): constexpr boost::array<int, 10> arr_std {{ 0,1,2,3,4,5,6,7,8,9 }}; int whatever [ arr.at(4) ]; -- Marshall Marshall Clow Idio Software <mailto:mclow.lists@gmail.com> A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait). -- Yu Suzuki

On Thu, Jan 10, 2013 at 11:16 PM, Marshall Clow <mclow.lists@gmail.com> wrote:
On Jan 10, 2013, at 9:06 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Here's my test case (using a locally modified Boost::Array): constexpr boost::array<int, 10> arr_std {{ 0,1,2,3,4,5,6,7,8,9 }}; int whatever [ arr.at(4) ];
FWIW, with gcc array size doesn't seem to have to be a constant expression. The following terminates because of throwing an exception: template< typename T, unsigned int n > struct array { constexpr array() {} constexpr T at(unsigned int i) const { return i < n ? T() : throw 0; } }; int main(int, char*[]) { constexpr array< int, 5 > arr; int whatever[arr.at(10)]; return whatever[0]; }
participants (6)
-
Andrey Semashev
-
Emil Dotchevski
-
Marshall Clow
-
Peter Dimov
-
Sebastian Redl
-
Vicente J. Botet Escriba