wikipedia (here) gives a compile time unrolling of for loop.......
i was wondering can we use a similar for loop with template statements inside...
for example...
is the following loop valid
template<int max_subdomain>
void Device<max_sudomain>::createSubDomains()
{
for(int i=0; i< max_subdomain; ++i)
{
SubDomain<i> tmp(member);
...
// some operations on tmp
...
}
}
SubDomain is a class which takes in the a template parameter int and here has been constructed with an argument that is a member of the Device class.
Thanks for the answer guys...
now that you know what i want...
is there anyway i achieve what i want to??
i finally got what i wanted..............
instead of using the for loop directly...
one can instead use the Boost::MPL for_each construct. I haven't yet implemented it but I am guessing that this provides a way to do what i wanted.....
I took the answer from another stack overflow question here... However the comment to the same question decries its use because it would be very slow (for large for loops of course)... however.. for loops which are not large i don't think there should be any bloating... i'll try the code and let you know the results....
the use is illustrated well in the example
There's a stadard solution for this. Convert iteration into recursion.
template<int i>
void Device::createSubDomains()
{
SubDomain<i> tmp(member);
// some operations on tmp
createSubDomains<i-1>();
}
template<>
void Device<-1>::createSubDomains()
{
// End of recursion.
}
Note: you can't use a runtime if(i!=0) createSubDomains<i-1>();.
2017 Note: you can now use a compile-time if constexpr(i!=0) createSubDomains<i-1>();
Even though you already accepted #iammilind 's answer, let me propose another one, because his reasoning for why i is not compile-time-constant is was not correct.
Suppose you have
template<unsigned int MAX> struct SubDomain {...};
...
and you want to declare an instance of it ...
SubDomain<i> tmp(member);
then i must be a commonly so-called compile-time-constant. What is that?
Pedantry
The standard assigns the term nontype template argument to template arguments that are not types (D'Oh).
14.3.2 Template non-type arguments [temp.arg.nontype]
A template-argument for a non-type, non-template template-parameter shall be one of:
— an integral constant-expression of integral or enumeration type; or
— ... [more follow, but are not relevant]
Right the first point contains a reference for further research: an integral constant-expression. This leads us to
5.19 Constant expressions [expr.const]
In several places, C + + requires expressions that evaluate to an integral or enumeration constant: as array
bounds (8.3.4, 5.3.4), as case expressions (6.4.2), as bit-field lengths (9.6), as enumerator initializers (7.2),
as static member initializers (9.4.2), and as integral or enumeration non-type template arguments (14.3).
Then, the key is:
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static
data members of integral or enumeration types initialized with constant expressions (8.5), non-type template
parameters of integral or enumeration types, and sizeof expressions.
Pedantry application
If we look back at your loop:
for (int i=...
...
SubDomain<i>
then we can now observe that i is not allowed there. Why? Because i is NOT a const variable.
The observing reader might now think you can circumvent this:
for (int i=...
...
const int I = i;
SubDomain<I>
But is this really allowed? Negative, I = i is not an integral constant-expression, because i is not. It helps to realise that the rule for integral constant-expressions is applied recursively.
E.g., the following is valid code:
template <int> void foo() {}
int main () {
const int ccI = 0;
const int ccJ = ccI*2;
const int ccK = ccJ/4;
foo<ccK>();
}
But if make just one part of the chain non-const, then ccK is not considered integral constant anymore:
template <int> void foo() {}
int main () {
int ccI = 0;
const int ccJ = ccI*2; // not compile time constant
const int ccK = ccJ/4; // same
foo<ccK>(); // error
}
Summary
So, in human readable form, template arguments that are not types, but (integer) values, must be compile-time-constant:
the initializer of a compile-time-constant must only involve other compile-time-constants
a literal value is a compile-time-constant
an enum value is a compile-time-constant
function-calls don't give compile-time-constants (for some advanced reasons)
Re-Edit:
My previous answer was correct. I have tried your code, it's giving compiler error. You cannot declare objects like that, as i cannot remain a compile time constant (as you are intending to do i++). template parameter must always be compile time constants. Here is the demo.
Also note that, loop unrolling is done for normal loops also, as part of optimization by compilers. It's not limited to templates.
Related
Consider the following two pieces of code:
template <int X>
struct Foo
{
enum
{
x = X
};
};
vs
template <int X>
struct Foo
{
static constexpr int x = X;
};
(The former is a frequent pattern in a library I want to modernize to C++17.)
I have looked through many questions/answers on here covering the differences between the enum vs static constexpr variants, but with C++17 having changed the behavior of static constexpr (by making such variables implicitly inline) many of them are outdated (example). It's not perfectly clear to me what the remaining differences are and if I am missing something important.
Is going from the first snippet above to the second a safe transformation? Or are there any potential breakages or changes in behavior affecting user code that I should be aware of?
It is incorrect to assume that the underlying type of the unscoped enum in the original struct is actually an int. As declared, the following applies:
Declares an unscoped enumeration type whose underlying type is not fixed (in this case, the underlying type is an implementation-defined integral type that can represent all enumerator values; this type is not larger than int unless the value of an enumerator cannot fit in an int or unsigned int
see: https://en.cppreference.com/w/cpp/language/enum
The type of the enum is actually undefined. Unscoped enums implicitly convert to integral types (and from there, can be converted to floating-point types) in calling code. It could also mean different compilers will create a different underlying type for the enum. By default; these two types are not interchangeable.
It should be safe, you just have limited what language standards allow your code to compile. If you don't want to restrict the code to only working in C++17, then you can use
template <int X>
struct Foo
{
static constexpr int x;
};
template <int X>
constexpr int Foo<X>::x = X;
This will allow the code to work with C++11. C++17 has an explicit exemption for this construct as it would break a lot of code if all of the sudden the out of line definitions cause an ODR violation.
Here are two line of code:
static const double RYDBERG_CONST_EV = 13.6056953;
static const char CHAR_H_EDGE = '-';
The second line compiles without errors, the first line does not compile. (Error: 'constexpr' needed for in-class initialization of static data member...)
The solution is apparently to add the keyword constexpr before the type. This is required because double is not an "integral type". But why does the behaviour differ between integer and floating point types?
I don't believe that there is a good reason for this except that it has grown historically.
The exception for integral types was desirable in pre-C++11 because people wanted to use them as array sizes. This goes along with the other exception for integral constants being treated as constant expressions. An exception that doesn't exist for floating-point types.
const int ni = 10;
const float nf = 10.0f;
int numbers1[(unsigned) ni]; // perfectly fine in all versions of C++
int numbers2[(unsigned) nf]; // error in all versions of C++
When C++11 introduced constexpr, it could do anything the special-casing for const integral types could do and much more. And it works the same way for any literal type. So, given a superior tool, there was no need to dilate the existing rules for integral types to floating-point.
Today, the special-casing of integral types is mostly a left-over from the earlier darker days. It cannot be removed from the language because doing so would break existing code that relies on this special-casing but there would be little gains from complicating the language even further by adding more exceptions that would be entirely unneeded today thanks to constexpr. People should be expected to migrate to constexpr and not worry about the old cruft any more. I believe that this was a very reasonable decision but you could certainly argue that another decision should have been made.
Addendum
As T.C. has commented, there has been a (non)-defect report about this issue where the committee confirmed that the behavior won't be changed and people are supposed to start using constexpr.
1826. const floating-point in constant expressions
Section: 5.20 [expr.const] Status: NAD Submitter: Ville Voutilainen Date: 2014-01-04
A const integer initialized with a constant can be used in constant expressions, but a const floating point variable initialized with a constant cannot. This was intentional, to be compatible with C++03 while encouraging the consistent use of constexpr. Some people have found this distinction to be surprising, however.
It was also observed that allowing const floating point variables as constant expressions would be an ABI-breaking change, since it would affect lambda capture.
One possibility might be to deprecate the use of const integral variables in constant expressions.
Additional note, April, 2015:
EWG requested CWG to allow use of const floating-point variables in constant expressions.
Rationale (May, 2015):
CWG felt that the current rules should not be changed and that programmers desiring floating point values to participate in constant expressions should use constexpr instead of const.
For the wording, § [class.static.data]/3 says:
If a non-volatile const static data member is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.20). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression.
(emph mine). Note how in case of integral types the static data member can, not must, have an initialization (you can always put it outside the class definition). Plus, the only other way to have an initaliation inside a class definition is by means of constexpr.
The reasoning (IMHO) about allowing integral types (also in C++98) to be initialized in the class definition is in order to enable very simple patterns like this:
class Foo {
static const size_t arrayLen = 42;
int foo[arrayLen];
};
which without an in-body initialization would become impossible to implement.
It is known that:
static const integral type members can be initialized in class definition.
static constexpr members can be initialized in class definition
double is not an integral type and should be marked as a constexpr.
Executables produced in a machine can run in other machines where floating point representation computation is different. Integral Constant Expressions do not change.
Marking an object static says that it can be known by all observers, and making it const is saying that the value does not change. The compiler can generate a value (e.g. 314 ) and put it in the read-only section, because the range is defined in the standard.
On the other hand double is not in the standard and cannot have its ranged check and the value stored at compile-time, in class definitions. One could easily end up with having different object files with objects having a different value for that static const double, thus breaking ODR.
Here is a simple example:
struct foo
{
static char const a = 1/11; // everyone gets 0 at compile-time
};
You would say then , but this can happen for doubles and at first look, something like this
struct foo
{
static double const y=1.0/11.0; // the true value is 0.090909...
};
seems verifiable, but the representation in double in one machine will be 0.09091 in another 0.090909091 .
Using constexpr permits to say to the compiler that the input necessary to verify this is available at compile-time . However, actual evaluation can happen at run-time.
Since object files produced by C++ compilers can move to machines with different floating point representations , you have to tell that this checking must be made during compile time to ensure that consistency.
The question is a typical example of an XY-problem. Instead of asking , "why do I have to mark anything with constexpr?" a puzzle char-vs-float is given. Now the question is, "why do we have to use constexpr for non-integral types?", and here you can find your answer .
I have problem understanding the following paragraph Per C++11 Standard N3485 Section 14.1.7.
I think it is more important to understand the rationale instead of memorizing the facts.
A non-type template-parameter shall not be declared to have floating point, class, or void type.
[ Example:
template<double d> class X; // error
template<double* pd> class Y; // OK
template<double& rd> class Z; // OK
—end example ]
I have some questions regarding this rule:
Is there a reason that why floating point type cannot be used as template parameter? What is the rationale behind that? I know this is true before C++11 and it seems also true for C++11 standard.
Why it is OK to use pointer or reference to floating point types as non-template parameters, but not raw floating point type? What is the big difference here?
Thank you for your help.
Is there a reason that why floating point type cannot be used as template parameter? What is the rationale behind that?
While I cannot give the ultimate reason, I can definitely imagine there would be problems with specializing a template that accepts a floating pointer value as a parameter.
Equality comparisons between floating point numbers is tricky (in the sense that it sometimes gives unexpected results), and when matching specializations, the compiler would have to perform an equality check between the argument provided and the value for which a template is being specialized.
Another similar issue is determining whether two instances of the same class templates are actually the same type:
template<double D>
struct X
{
// ...
};
int main()
{
X<3.0> x;
X<some_constant_expression()> y;
}
Are x and y instances of the same class? To decide this, an equality check has to be performed between 3.0 and some_constant_expression().
Why it is OK to use pointer or reference to floating point types as non-template parameters, but not raw floating point type?
With respect to the above scenario, the answer concerning pointers is simple: pointers are integral values, and comparison between pointers is well defined.
Concerning references, evidence shows that they are in fact treated like pointers:
#include <type_traits>
double a = 0.0;
double b = 0.0;
template<double& D>
struct X : std::false_type { };
template<>
struct X<a> : std::true_type { }
int main()
{
static_assert(X<a>::value, "!"); // Does not fire
static_assert(X<b>::value, "!"); // Fires
}
Also, per paragraph 14.4/1 of the C++11 Standard:
Two template-ids refer to the same class or function if
— [...]
— their corresponding non-type template arguments of integral or enumeration type have identical values and
— [...]
— their corresponding non-type template-arguments of reference type refer to the same external object
or function and
— [...]
[ Example:
template<class E, int size> class buffer { / ... / };
buffer<char,2*512> x;
buffer<char,1024> y;
declares x and y to be of the same type, and [...]
The above shows that determining whether two different instances of the same class template are actually the same class requires an equality check between the constant expressions used as template arguments.
To figure this out, consider that integral types and pointers always have a one-to-one relationship with their literal representation.
But then let's consider a non-type template Foo<float>.
Let's say it's specialized for a non-binary-representable numver like 0.1: Foo<0.1> and let's say the compiler decorates the symbol name based on the specialization and you wind up with something like Foo_3DCCCCCC because the compiler is using "round down" for an IEEE 754 32 bit rep.
But then let's say that the user of this code is compiling is such a way that the compiler chooses "round to positive infinity" instead. Then then specialization's name is instead Foo_3DCCCCCD which is a completely different function from the one that was previously specialized in another translation unit.
Unless you start making up a wide variety of rules to handle all these sorts of things (what about NaN, infinity, and other not-a-normal-numbers?) then you open yourself to mismatches and all sorts of possible problems.
I was reading an article about non-type template arguments, and it said that :
When being instantiated, only compile time constant integer can be passed. This means 100, 100+99, 1<<3 etc are allowed, since they are compiled time constant expressions. Arguments, that involve function call, like abs(-120), are not allowed.
Example :
template<class T, int SIZE>
class Array{};
int main(){
Array<int, 100+99> my_array; // allowed
Array<int, abs(-120)> my_array; // not allowed
}
what's the difference between 100+99 and abs(-120) ?
how come 100+99 are compiled time and abs(-120) is not?
None, and abs(-120) is entirely legal in C++11. C++03, as you adequately point out, did not have scope for functions which could evaluate at compile-time, but C++11 does. For abs directly, you could replace it with a template which performs the same computation and use abs_template<-120>::value in C++03.
Edit: I meant to say that, even if abs was not constexpr, you could trivially write your own abs which is constexpr. Coulda sworn I edited that in.
100+99 is optimized out to 199 at compile time.
abs() is function and it may or may not be marked constexpr (C++11 feature, that would allow you to do so; you can easily check cppreference or standard to see if it's constexpr in C++11). It requires to be executed; compiler cannot deduce that it's state less function returning same value for every run with same argument.
I would like to define inside a class a constant which value is the maximum possible int. Something like this:
class A
{
...
static const int ERROR_VALUE = std::numeric_limits<int>::max();
...
}
This declaration fails to compile with the following message:
numeric.cpp:8: error: 'std::numeric_limits::max()' cannot appear in a constant-expression
numeric.cpp:8: error: a function call cannot appear in a constant-expression
I understand why this doesn't work, but two things look weird to me:
It seems to me a natural decision to use the value in constant expressions. Why did the language designers decide to make max() a function thus not allowing this usage?
The spec claims in 18.2.1 that
For all members declared static const in the numeric_limits template, specializations shall define these values in such a way that they are usable as integral constant expressions.
Doesn't it mean that I should be able to use it in my scenario and doesn't it contradict the error message?
Thank you.
Looks like a bit of a defect...
In C++0x, numeric_limits will have everything marked with constexpr, meaning you will be able to use min() and max() as compile-time constants.
While the current standard lacks support here, for integral types Boost.IntegerTraits gives you the compile time constants const_min and const_max.
The problem arises from §9.4.2/4:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions.
Note that it adds:
The member shall still be defined in a name- space scope if it is used in the program and the namespace scope definition shall not contain an initializer.
As others already mentioned numeric_limits min() and max() simply aren't integral constant expressions, i.e. compile time constants.
You want:
#include <limits>
struct A {
static const int ERROR_VALUE;
};
const int A::ERROR_VALUE = std::numeric_limits<int>::max();
Put the class/struct in a header and the definition in a .cpp file.
It doesn't contradict, because max is not defined static const. It's just a static member function. Functions can't be const, and static member functions can't have a const attached at the very right either.
There is also a double max() in the double version of the limits, and in C++03 it wouldn't work to say static double const max = .... So to be consistent, max() is a function for all versions of the limit template.
Now, it's known that max() not being able to be used like that is bad, and C++0x already solves it by making it a constexpr function, allowing your proposed usage.
I will try to answer you as much as I understood from your question:
1- If you want a static const int in your program to be initialized with a function:
int Data()
{
return rand();
}
class A
{
public :
static const int ee;
};
const int A::ee=Data();
This works on VS 2008
2- If you want to get max and min number for a given data type, then use these definitions
INT_MAX, INT_MIN, LONG_MAX and so on..
3- If however you need to use these wrt template type, then
hard code the templates yourself
template<>
int MaxData()
{
return INT_MAX;
}
and
template<>
long MaxData()
{
return LONG_MAX ;
}
and call them like this
int y=MaxData<int>();
4- and if you are only dealing with binary represented types only, then use this:
template <class T>
T MaxData(){
return ~(1<<((sizeof(T)*8)-1));
}
and this
template <class T>
T MinData(){
return (1<<((sizeof(T)*8)-1));
}
Hope this can help you..