Boost.Exception and constexpr

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
23 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Boost.Exception and constexpr

Marshall Clow-2
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:[hidden email]>

A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait).
        -- Yu Suzuki


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Emil Dotchevski-3
On Wed, Jan 9, 2013 at 6:23 PM, Marshall Clow <[hidden email]> 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

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Vicente Botet
Le 10/01/13 07:44, Emil Dotchevski a écrit :
> On Wed, Jan 9, 2013 at 6:23 PM, Marshall Clow <[hidden email]> 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

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Peter Dimov-2
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.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
On Thu, Jan 10, 2013 at 3:11 PM, Peter Dimov <[hidden email]> 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.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Peter Dimov-2
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 );
}


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Peter Dimov-2
> 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))


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
In reply to this post by Peter Dimov-2
On Thu, Jan 10, 2013 at 3:47 PM, Peter Dimov <[hidden email]> 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.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Sebastian Redl
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

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
On Thu, Jan 10, 2013 at 6:22 PM, Sebastian Redl
<[hidden email]> 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.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Sebastian Redl
On 10.01.2013 15:46, Andrey Semashev wrote:

> 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
line above was supposed to be a typedef?

Sebastian

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
On Thu, Jan 10, 2013 at 6:53 PM, Sebastian Redl
<[hidden email]> 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.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Vicente Botet
In reply to this post by Andrey Semashev-2
Le 10/01/13 15:46, Andrey Semashev a écrit :

> On Thu, Jan 10, 2013 at 6:22 PM, Sebastian Redl
> <[hidden email]> 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

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Peter Dimov-2
In reply to this post by Peter Dimov-2
> 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.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
In reply to this post by Vicente Botet
On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba
<[hidden email]> wrote:
>
> Have you tried declaring arr as a constexpr?

It doesn't make any difference, the error is the same.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Vicente Botet
Le 10/01/13 19:13, Andrey Semashev a écrit :
> On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba
> <[hidden email]> 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(); // ***************
}

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba
<[hidden email]> wrote:

> Le 10/01/13 19:13, Andrey Semashev a écrit :
>
>> On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba
>> <[hidden email]> 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...

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Marshall Clow-2
In reply to this post by Vicente Botet
On Jan 10, 2013, at 9:06 AM, Vicente J. Botet Escriba <[hidden email]> wrote:

> Le 10/01/13 15:46, Andrey Semashev a écrit :
>> On Thu, Jan 10, 2013 at 6:22 PM, Sebastian Redl
>> <[hidden email]> 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:[hidden email]>

A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait).
        -- Yu Suzuki


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Vicente Botet
In reply to this post by Andrey Semashev-2
Le 10/01/13 20:12, Andrey Semashev a écrit :

> On Thu, Jan 10, 2013 at 10:51 PM, Vicente J. Botet Escriba
> <[hidden email]> wrote:
>> Le 10/01/13 19:13, Andrey Semashev a écrit :
>>
>>> On Thu, Jan 10, 2013 at 9:06 PM, Vicente J. Botet Escriba
>>> <[hidden email]> 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

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Exception and constexpr

Andrey Semashev-2
In reply to this post by Marshall Clow-2
On Thu, Jan 10, 2013 at 11:16 PM, Marshall Clow <[hidden email]> wrote:
> On Jan 10, 2013, at 9:06 AM, Vicente J. Botet Escriba <[hidden email]> 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];
}

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
12