Why is this not constexpr?

Hi,

I have a native array at global scope whose size is known at compile time:

const std::type_info* intsRtti[Length<SignedIntegers>::value];



I understand this to mean that the address of intsRtti is known at compile time (right?)

If I define a constexpr function like so:

constexpr const std::type_info** next(const std::type_info** start)
{
return start + sizeof(void*);
}

and call it from inside a template where the parameter is known at compile time:

template<class H, class NH, class T, const std::type_info** start_address>
struct AssignEff< Typelist<H, Typelist<NH, T>>, start_address>
{
static enum { next_address = next(start_address) };
using Base = AssignEff<Typelist<NH, T>, nex_address>;
/// .....

I get an error in the line I try to use next():


"expression did not evaluate to a constant"

Why is this? I understood a constexpr function returns a constant if it is called with a compile time constant....

Regards,
Juan
const std::type_info* intsRtti[Length<SignedIntegers>::value];

I understand this to mean that the address of intsRtti is known at compile time (right?)

No. Addresses don't exist until a program is loaded into memory so they cannot be known at compile time.
One question:

if an address is not known at compile time, why is it that an address is acceptable as a template parameter? And, given that it is accepted, why is another address (the result of the function next above) not suitable when we calculate it by adding a compile time offset (i.e. sizeof(void*)) to the original address received as a template argument?

In the exact context of my sample on my original question, why can I not calculate a 'next_address' from a 'start_address' by applying such a simple function (next) to 'start_address'?

All I wanted is to calculate a different address for my next recursion of the template, like so:

enum { next_address = next(start_address) };
using Base = AssignEff<Typelist<NH, T>, next_address>;


Thanks in advance!!
Juan
Last edited on
> if an address is not known at compile time, why is it that and address is acceptable as a template parameter?

The address of an object with static storage duration is a core constant expression.

Reference constant expression
Reference constant expression is an lvalue core constant expression that designates an object with static storage duration or a function.

Address constant expression
Address constant expression is a prvalue core constant expression (after conversions required by context) of type std::nullptr_t or of a pointer type, which points to an object with static storage duration, one past the end of an array with static storage duration, to a function, or is a null pointer.

http://en.cppreference.com/w/cpp/language/constant_expression


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <type_traits>

using ptr_const_int = const int* ;
using ptr_ptr_const_int = const ptr_const_int* ;

constexpr int a[] = { 0, 1, 2, 3, 4 } ;
constexpr ptr_const_int address_a = a ;
constexpr ptr_const_int foo( ptr_const_int x, std::size_t n ) { return x+n ; }

constexpr ptr_const_int b[] = { a, a+1, a+2, a+3, a+4 } ;
constexpr ptr_ptr_const_int address_b = b ;
constexpr ptr_ptr_const_int foo( ptr_ptr_const_int x, std::size_t n ) { return x+n ; }

int main()
{
    char cstr[ *foo( address_a, 2 ) + **foo( address_b, 1 ) ] {} ;
    using constant = std::integral_constant< std::size_t, *foo( address_a, 1 ) + **foo( address_b, 2 ) > ;
    enum test { test_it = *foo( address_a, 2 ) + **foo( address_b, 4 ) } ;
    
    static_assert( sizeof(cstr) == constant::value, "must be equal" ) ;
    static_assert( test_it == 6, "must be 6" ) ;
}

http://coliru.stacked-crooked.com/a/738c1dd5e07d2154

The Microsoft compiler chokes on this; with Visual Studio, use the clang++ front-end.
I could not get this sample to compile in Visual Studio 2015 Update 2 - complains that

expression did not evaluate to a constant
referring to the size initializer to the char cstr array.

So I tried to compile with the option Clang 3.7 with Microsoft CodeGen but I got tons of error messages from the included files (type_traits and what that includes).

Microsoft seems to have a real problem with constexpr, doesn't it?

Is this sample supposed to compile correctly in Standard C++ 11?

Thanks,
Juan
> I got tons of error messages from the included files (type_traits and what that includes).

Enable rtti (to use typeid)
Project => Properties => C++ => Language => Enable Run-time Type Information: Yes (-frtti)


Just tried this; it compiles cleanly with Visual Studio 2015 Update 2 (+ the recent patch),
and Clang 3.7 with Microsoft CodeGen (the latest update), and -frtti

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <type_traits>
#include <typeinfo>
#include <cassert>

using ptr_typeinfo = const std::type_info* ;

constexpr ptr_typeinfo tinfo[] { &typeid(short), &typeid(int), &typeid(long), &typeid( long long ) } ;
constexpr const ptr_typeinfo* begin = tinfo ;

constexpr const ptr_typeinfo* next( const ptr_typeinfo* start ) { return start + 1 ; }

int main()
{
    constexpr std::size_t N = next( next( next( next(begin) ) ) ) - begin ;
    static_assert( N == sizeof(tinfo) / sizeof( *tinfo ), "must be four" ) ; // compile-time assertion
    assert( **next( next(begin) ) == typeid(long) ) ; // run-time assertion
}
Last edited on
Yes it compiles fine with latest patch!!

Thanks

Juan
Topic archived. No new replies allowed.