Pages: [1]   Go Down
Author Topic: Templates and __builtin-constant_p  (Read 1404 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm trying to get code similar to this to compile:
Code:
template<bool Flag> struct foo {static const bool bar = Flag;};
int main() {
    int a;
    int baz = foo<__builtin_constant_p(a)>::bar;
}
Code:
minimal.cpp: In function ‘int main()’:
minimal.cpp:4:42: error: the value of ‘a’ is not usable in a constant expression
minimal.cpp:3:9: note: ‘int a’ is not const
minimal.cpp:4:42: note: in template argument for type ‘bool’

It should be that, whether or not a is constant, <whether or not a is constant> should be constant --- ie, the output of __builtin_constant_p() should always be constant and able to be used in a template. However, while the output of __builtin_constant_p(__builtin_constant_p(a)) is always 1 no matter what the type of a, I still get the above error.

Does anyone have a solution for this so that I can determine whether or not to use a template depending on if a value is constant and thus is legal to use a template?
Logged

Offline Offline
Full Member
***
Karma: 2
Posts: 212
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

maybe this is of any help to you ?
http://www.cplusplus.com/doc/tutorial/templates/
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46240
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    int a;
Local variables are not initialized, unless you provide an initial value.

Code:
    int baz = foo<__builtin_constant_p(a)>::bar;
Why would you pass an uninitialized variable to any kind of function, constant or not?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
template<bool Flag> struct foo {static const bool bar = Flag;};
int main() {
    int a;
    int baz = foo<__builtin_constant_p(a)>::bar;
}

Under IDE 1.0.1:

Code:
sketch_oct01b.cpp:7: sorry, unimplemented: call_expr cannot be mangled due to a defect in the C++ ABI

At least they apologised!
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you are misusing Flag in your first line. Can you explain what the intention is?
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 53
Posts: 1801
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Not possible sorry, join my band wagon and encourage Arduino to accept c++11, the constexpr keyword is what you are looking for. I'm pretty sure its just a command line flag change.

C++, as  a rule instantiates everything at compile time ( its how it can optimise ), templates however cannot be instantiated until parameters are provided. So each specific variation of a template is specific to its parameters. Which means you cannot instantiate a  template at runtime as there is no specific parameters compiled for it.

Mutable variables are not considered compile time constants. Even when marked as const ( taking the address can allow changing of the data )

Logged


Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    int a;
Local variables are not initialized, unless you provide an initial value.

Code:
    int baz = foo<__builtin_constant_p(a)>::bar;
Why would you pass an uninitialized variable to any kind of function, constant or not?

To show an minimal example of my problem.

Code:
template<bool Flag> struct foo {static const bool bar = Flag;};
int main() {
    int a;
    int baz = foo<__builtin_constant_p(a)>::bar;
}

Under IDE 1.0.1:

Code:
sketch_oct01b.cpp:7: sorry, unimplemented: call_expr cannot be mangled due to a defect in the C++ ABI

At least they apologised!

It works in gcc 4.7.1, which I have. I guess the gcc people can implement things given 4 years (gcc 4.3.2 was released August 27, 2008)

I think you are misusing Flag in your first line. Can you explain what the intention is?

Well the intention is to use a different struct from that one: http://arduino.cc/forum/index.php/topic,124974

Not possible sorry, join my band wagon and encourage Arduino to accept c++11, the constexpr keyword is what you are looking for. I'm pretty sure its just a command line flag change.

C++, as  a rule instantiates everything at compile time ( its how it can optimise ), templates however cannot be instantiated until parameters are provided. So each specific variation of a template is specific to its parameters. Which means you cannot instantiate a  template at runtime as there is no specific parameters compiled for it.

Mutable variables are not considered compile time constants. Even when marked as const ( taking the address can allow changing of the data )

Well I'm no expert in C++11, but when I try to compile the same program with "-std=c++11" or "-std=gnu++11" I get the same errors. Do you mean that __builtin_constant_p() should be declared constexpr? It's a gcc builtin, so it's not a true function.

Also, the same program does compile without optimizations (with __builtin_constant_p(a) returning 0), and this does compile with __builtin_constant_p(a) as 1. So it's not a problem that the return of __builtin_constant_p() is not constant, it's that it's sometimes constant.
Code:
template<bool Flag> struct foo {static const bool bar = Flag;};
int main() {
    const int a = 4;
    int baz = foo<__builtin_constant_p(a)>::bar;
}

I'm thinking I'll report it as a bug in gcc, since there's no reason why __builtin_constant_p() would ever return a non-constant.



If nobody thinks that it's possible to make that program work, my next question is "How can I make a variable one type if a different one is constant and a different one if it's not?"
ie, get a to be an int if b is constant, and a to be a long if b is not constant.
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 53
Posts: 1801
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not sure if you realise, but my class 'BestFitUInt' is a template metaprogram, it runs entirely during compile time. The class evaporates before runtime leaving you with a 'type' used to declare variables.

With constexpr, you wouldn't need to use templates. The compiler could get the code as close to static as possible while allowing t to be implemented dynamically, still would not be as efficient and most probably equal to making a runtime version of BestFitUInt.
Logged


North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 53
Posts: 1801
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh, and no its not a bug. The compiler ( and __builtin_constant_p ) cannot guarantee 'a' is a compile time constant within its current context.

Haven't tried it but,
Code:
typedef IF< __builtin_constant_p( a ), int, long >::Result NumType;
NumType n_Number = 4;
« Last Edit: September 30, 2012, 07:13:00 pm by pYro_65 » Logged


Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh, and no its not a bug. The compiler ( and __builtin_constant_p ) cannot guarantee 'a' is a compile time constant within its current context.
Can you explain that a little more? I know the output of __builtin_constant_p is sometimes constant, but it isn't always. I would think all the compiler needs to know to figure out if it's constant is if it has the "const" attribute or is a literal, but does it need more than that?
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 53
Posts: 1801
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you ever written lots of functions without compiling. Then in your ( lets say loop() ) function you use a couple of the functions and compile. Everything goes well so you add in the remainder functions and suddenly you get a syntax/compile error. Even though the function was defined with the error previously, because it wasn't referenced it didn't pass through the compiler.

In reference to __builtin_constant_p, it is seeing 'a' before it has seen the remainder of the function. I think this is hard/impossible to get around.

This is just a thought,
If 'foo' was a type based template, you could create a forward declaration of 'foo'. You can now but it would require a forward declaration for every possible value of 't', which might not be such a bad idea for a range of possible 't'.

But I still don't think you will have luck as the compiler is linear, it still can't guarantee 'a' will not get assigned a value on the next line of code. Even though optimisations can pass many times, __builtin_constant_p is evaluated once.
« Last Edit: September 30, 2012, 08:18:42 pm by pYro_65 » Logged


Pages: [1]   Go Up
Jump to: