Go Down

Topic: Templates and __builtin-constant_p (Read 2153 times) previous topic - next topic

WizenedEE

I'm trying to get code similar to this to compile:
Code: [Select]

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

Code: [Select]

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?

PGT

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

PaulS

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

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

Nick Gammon

Code: [Select]

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: [Select]

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


At least they apologised!
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

I think you are misusing Flag in your first line. Can you explain what the intention is?
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

pYro_65

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 )


WizenedEE


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

Code: [Select]
    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: [Select]

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: [Select]

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: [Select]

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.

pYro_65

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.

pYro_65

#8
Oct 01, 2012, 02:10 am Last Edit: Oct 01, 2012, 02:13 am by pYro_65 Reason: 1
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: [Select]
typedef IF< __builtin_constant_p( a ), int, long >::Result NumType;
NumType n_Number = 4;

WizenedEE


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?

pYro_65

#10
Oct 01, 2012, 03:11 am Last Edit: Oct 01, 2012, 03:18 am by pYro_65 Reason: 1
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.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy