Why main can not be a constexpr? - c++

When you attempt to use constexpr with main like this:
constexpr int main()
gcc and clang complain:
error: cannot declare '::main' to be inline
error: 'main' is not allowed to be declared constexpr
Let's see what requirements for constexpr function are:
A constexpr function must satisfy the following requirements:
it must not be virtual
its return type must be LiteralType
each of its parameters must be literal type
What is LiteralType?
A literal type is any of the following
void(since c++14)
scalar type
reference type
an array of literal type
What must the function body include?
null statements
static_assert declarations
typedef declarations and alias declarations that do not define classes or enumerations
using declarations
using directives
exactly one return statement that contains only literal values, constexpr variables and functions.
The following examples:
constexpr int main() { ; }
constexpr int main() { return 42; }
constexpr int main() {
// main defaults to return 0
}
seems to fit all these requirements. Also with that, main is special function that runs at start of program before everything else. You can run constexpr functions from main, and in order for something marked constexpr to be constexpr, it must be run in a constexpr context.
So why is main not allowed to be a constexpr?

No, this is not allowed the draft C++ standard in section 3.6.1 Main function paragraph 3 says:
[...]A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed.[...]
main has to be a run-time function and as Lightness says it makes no sense since you can't optimize main away.

The standard gives the precise signature for main, so the compiler is allowed to reject other signatures. Even more specifically, it prescribes that main cannot be constexpr, static, or some other things.
If you're wondering why, the compiler is allowed to insert code at the beginning of main (to do stuff like initialize global variables, etc.) which could make it non-constexpr (which is why e.g. a program is not allowed to call main explicitly).

It doesn't make any sense to declare main as constexpr for two reasons: 1) It is a run-time function. 2) it may not be called from other functions or recursively.

In my opinion the reason is that it makes no sense to declare main() as a constexpr and the standards committee want the C++ programming language to make sense.
The function main() is a special function that deals with program entry-point initialization - it is not sensible to use it to calculate compile-time values.

Related

Static and non-static member function templates with the same parameter types and requires clause in C++

Static and non-static member functions with the same parameter types cannot be overloaded. But if member functions are templates and one of them has requires clause then all compilers allow it. But the problems appear when one calls both of the member functions:
struct A {
static int f(auto) { return 1; }
int f(auto) requires true { return 2; }
};
int main() {
[[maybe_unused]] int (A::*y)(int) = &A::f; // ok everywhere (if no below line)
[[maybe_unused]] int (*x)(int) = &A::f; //ok in GCC and Clang (if no above line)
}
If only one (any) line is left in main() then GCC and Clang accept the program. But when both lines in main() are present, Clang prints
error: definition with same mangled name '_ZN1A1fIiEEiT_' as another definition
and GCC reports an internal compiler error. Demo: https://gcc.godbolt.org/z/4c1z7fWvx
Are all compilers wrong in accepting struct A definition with overloaded static and not-static member functions? Or they just have similar bugs in the calling of both functions.
This is quite messy! While skimming through the standard, I found this much simpler example in [over.over]:
struct X {
int f(int);
static int f(long);
};
int (X::*p1)(int) = &X::f; // OK
int (*p2)(int) = &X::f; // error: mismatch
int (*p3)(long) = &X::f; // OK
So I first tried the two valid lines, but even they are rejected (independently of each other) by all three compilers. That is a problem.
Looking further, about the address of function templates, [temp.deduct.funcaddr] says:
Template arguments can be deduced from the type specified when taking the address of an overload set.
If there is a target, the function template's function type and the target type are used as the types of P and A, and the deduction is done as described in [temp.deduct.type].
Otherwise, deduction is performed with empty sets of types P and A.
Such targets are described in [over.over], and in your example are of the first type:
(1.1)
an object or reference being initialized ([dcl.init], [dcl.init.ref], [dcl.init.list]),
Even before considering any constraints, it seems to me that a compiler should be able to identify a unique candidate in both of your cases, just as in the simpler examples, given that the targets have different signatures.
According to the latest draft of C++20 standard, class.static.mfct#2:
There shall not be a static and a non-static member function with the same name and the same parameter types ([over.load]).
There is no exception here for the presence of requires-clause to differentiate member functions, only same name and the same parameter types. So the definition of struct A is malformed in C++20.
The same item was rephrased In the first draft of C++23, class.static.mfct#2
There cannot be a static and a non-static member function with the same name, parameter-type-list, and trailing requires-clause ([over.load]).
According to this, the definition of A is already fine. And it looks like GCC, Clang, and MSVC all follow this statement even in C++20 mode. And the errors we observe happen because of same mangled names of both functions (which hardly can be fixed preserving the current ABI).
And in the latest draft of C++, class.static.mfct#2 any restriction on having static and not-static member functions with same name and parameters are removed.

Would it be sufficient for constexpr, consteval, and constinit to be definitions instead of keywords?

It seems that the rules for the compile-time keywords: constexpr, consteval and constinit are defined well enough for compilers to warn if you misapply the label.
It would make sense that (much like inline) the compiler can, in all places, apply rules to determine if, in fact, code could have one of the compile-time keywords applied and, be forced, per language specification, to compile as much as possible as if the compile-time keywords had been applied.
Or, at a minimum, if a compile-time keyword is applied to a function and the code would have qualified with had the correct compile-time keywords been applied. Compile that function, as if all the functions called had the correct compile-time keywords.
Here is a simple example:
#include <tuple>
consteval std::tuple<int, int> init1(int x, int y)
{
return {x,y};
}
std::tuple<int, int>& foo1()
{
static constinit std::tuple<int, int> x=init1(1,2);
return x;
}
std::tuple<int, int> init2(int x, int y)
{
return {x,y};
}
std::tuple<int, int>& foo2()
{
static std::tuple<int, int> x=init2(1,2);
return x;
}
static std::tuple<int, int> x3=init2(1,2);
std::tuple<int, int>& foo3()
{
return x3;
}
see it here: https://godbolt.org/z/KrzGfnEo7
Note that init1/foo1 are fully specified with compile-time keywords and there is no need for a guard variable, since it is initialized completely (not just 0 filled).
The question is about why the compiler doesn't do the same in the cases of init2/foo2 or x3/foo3? Or more precisely why the compiler is allowed NOT to initialize fully at compile time.
EDIT (as per comment) see (Why do we need to mark functions as constexpr?) constexpr would be required. I am concerned more with cases of consteval and constinit. Could the specification be modified to require trying to resolve code at compile-time and not failing because of the absence of constexpr? This would allow interface contracts to just use constexpr as per the related question.
Or, at a minimum, if a compile-time keyword is applied to a function and the code would have qualified with had the correct compile-time keywords been applied.
The basis of your question is the assumption that these keywords are just variations on a theme, that a function which could have some of them ought to have a specific one based on the properties within the function alone.
That's not reasonable.
For functions, any function which could be constexpr could also be consteval. The difference is that one can be called during constant expression evaluation, and the other must be called only during constant expression evaluation. This is not an intrinsic property of the function definition; it is about how the function is to be used.
The compiler should not override the decision of a programmer to be able to use a function at runtime just because the function definition just so happens to also be legit for consteval.
It should also be noted that there is the requirements of a function definition for a consteval function are the same as for a constexpr function.
It is also not possible to know if a function definition ought to be constexpr or not. Remember: while a constexpr function explicitly forbids certain constructs from appearing in the definition, it also permits you to have certain constructs in the definition that aren't allowed to be evaluated during constant evaluation... so long as you never actually allow those code paths to be evaluated during constant evaluation. So there are many function definitions that just so happen to be valid for constexpr even if the programmer didn't intend for them to be evaluated at compile-time.
Lambdas get implicit constexpr definitions only because space in a lambda expression is at a premium.
For variables, implicit constexpr makes even less sense. A variable ought to be constexpr if you intend to use it in a constant expression later on. This requires it to have an initializer that is a constant expression. Implicit constexpr is a problem because you might start relying on the implicit constexpr rule, then change the initializer to no longer be a constant expression and get a strange error in the place where you used its constexpr properties.
It's better to make the user be explicit up-front than to misjudge what the user was trying to do and make a user think something is supposed to be valid when it wasn't intended.
And constinit is solely about ensuring that a user never accidentally uses a non-constant expression to initialize the variable. Making it implicit would make absolutely no sense, as changing the expression to no longer be a constant expression wouldn't cause compilation to fail. Compilers are smart enough to know when a variable is initialized with a constant expression and can decide how to handle that on its own.

GNU const/pure attributes vs constexpr

GNU C and C++ offer the const and pure function attributes.
From the gnu online docs (emphasis mine):
In GNU C and C++, you can use function attributes to specify certain function properties that may help the compiler optimize calls or check code more carefully for correctness. For example, you can use attributes to specify that a function never returns (noreturn), returns a value depending only on the values of its arguments (const), or has printf-style arguments (format).
Where the const attribute seems to be a subset to pure, also taken from the gnu docs:
The const attribute imposes greater restrictions on a function’s
definition than the similar pure attribute. Declaring the same
function with both the const and the pure attribute is diagnosed.
With C++ 11, the constexpr specifier was added.
When applied to functions, is there a difference between the const attribute and the constexpr specifier? Does GCC apply different optimizations?
A similar sounding question is Difference between `constexpr` and `const` . But I think this is not a duplicate. My question is specifically about the function attribute const, which seems to have overlapping functionality with constexpr.
When applied to functions, is there a difference between the const attribute and the constexpr specifier?
There are differences.
Firstly, C does not have constexpr, so you cannot take advantage of it in that language.
Calls to constexpr function can be constant expressions. As such, their result can be used for example as the size of an array. The GNU attributes cannot be used to achieve the same (ignoring GCC VLA language extension).
Constexpr functions are good for taking advantage of pre-calculation at compile time. The GNU attributes are still useful for allowing the compiler take advantage of runtime constness. For example, let's say there is a function that cannot be constexpr - perhaps because it calls a non-constexpr function. But we may know that every call to the function produces same output with no side-effects. Const attribute allows the compiler to not repeat redundant calls.
Another difference is that constexpr functions must be defined inline. Non-constexpr functions don't need to be defined inline.
There is very little overlap between the them. Here is a function that is gnu::const (and therefore gnu::pure) but cannot be constexpr:
[[gnu::const]] int f() {
struct s {
int m;
};
union {
s a;
s b;
};
a.m = 1;
return b.m;
}
You cannot read from the common initial subsequence of a union in a constant expression, so this function never produces a constant expression.
The following is a function that is constexpr but cannot be gnu::pure (and therefore cannot be gnu::const):
constexpr void f(int & x) {
x = 1;
}
This writes to memory, which gnu::pure functions cannot do.
constexpr just means that it can be called at compile time. This has overlap with gnu::const and gnu::pure in that you cannot write to global variables or access volatile memory (all IO operations access volatile memory from C++'s point of view), but they each have other restrictions that make them distinct.
In C++11, constexpr was much more limited. You could not write to any reference parameters, so I think C++11 constexpr was a strict subset of gnu::pure. The following is an example of a C++11 constexpr function that cannot be marked gnu::const, however:
[[gnu::pure]] constexpr int f(int const & x) {
return x;
}
Another difference is that a __attribute__ ((const)) function must return the same output value for the same argument (if I am not wrong; it's the first time I see this attribute ;). That does not need to hold for constexpr functions.
An academic example:
constexpr int rand(int n)
{
std::string_view sv(__TIME__);
return sv.back() % n;
}
std::array<int, rand(10) + 1> a; // exemplary usage
Though rand is constexpr, it may produce different output for the same input argument.

Why can you initialize a static const variable inline but not a plain static (C++)

If I were to do this
class Gone
{
public:
static const int a = 3;
}
it works but if do
class Gone
{
public:
static int a = 3;
}
it gives a compile error. Now I know why the second one doesn't work, I just don't know why the first one does.
Thanks in advance.
This trick works only for constant compile-time expressions. Consider the following simple example:
#include <iostream>
class Foo {
public:
static const int bar = 0;
};
int main()
{
std::cout << Foo::bar << endl;
}
It works just fine, because compiler knows that Foo::bar is 0 and never changes. Thus, it optimizes the whole thing away.
However, the whole thing breaks once you take the address of that variable like this:
int main()
{
std::cout << Foo::bar << " (" << &Foo::bar << ")" << std::endl;
}
Linker sends you to fix the program because compile-time constants don't have addresses.
Now, the second case in your example doesn't work simply because a non-constant variable cannot be a constant compile-time expression. Thus, you have to define it somewhere and cannot assign any values in initialization.
C++11, by the way, has constexpr. You can check Generalized constant expressions wiki (or C++11 standard :-)) for more info.
Also, be careful - with some toolchains you will never be able to link program as listed in your first example when optimizations are turned off, even if you never take an address of those variables. I think there is a BOOST_STATIC_CONSTANT macro in Boost to work around this problem (not sure if it works though because I reckon seeing linkage failures with some old gcc even with that macro).
The static const int declaration is legal because you're declaring a constant, not a variable. a doesn't exist as a variable - the compiler is free to optimize it out, replacing it with the declared value 3 anywhere a reference to Gone::a appears. C++ allows the static initialization in this restricted case where it's an integer constant.
You can find more details, including an ISO C++ standard citation here.
Initialization of variables has to be done at the point of definition, not the point of declaration in the general case. Inside the class brackets you only have a declaration and you need to provide a definition in a single translation unit*:
// can be in multiple translation units (i.e. a header included in different .cpp's)
struct test {
static int x; // declaration
static double d; // declaration
};
// in a single translation unit in your program (i.e. a single .cpp file)
int test::x = 5; // definition, can have initialization
double test::d = 5.0; // definition
That being said, there is an exception for static integral constants (and only integral constants) where you can provide the value of the constant in the declaration. The reason for the exception is that it can be used as a compile-time constant (i.e. to define the size of an array), and that is only possible if the compiler sees the value of the constant in all translation units where it is needed.
struct test {
static const int x = 5; // declaration with initialization
};
const int test::x; // definition, cannot have initialization
Going back to the original question:
Why is it not allowed for non-const integers?
because initialization happens in the definition and not declaration.
Why is it allowed for integral constants?
so that it can be used as a compile-time constant in all translation units
* The actual rules require the definition whenever the member attribute is used in the program. Now the definition of used is a bit tricky in C++03 as it might not be all that intuitive, for example the use of that constant as an rvalue does not constitute use according to the standard. In C++11 the term used has been replaced with odr-used in an attempt to avoid confusion.
A static const is defined in the class definition since everybody that uses the code need to know the value at compile time, not link time. An ordinary static is actually only declared in the class definition, but defined once, in one translation unit.
I seem to recall that originally (ARM) it was not allowed, and we used to use enum to define constants in class declarations.
The const case was explicitly introduced so as to support availability of the value in headers for use in constant expressions, such as array sizes.
I think (and please comment if I have this wrong) that strictly you still need to define the value:
const int Gone::a;
to comply with the One Definition Rule. However, in practice, you might find that the compiler optimises away the need for an address for Gone::a and you get away without it.
If you take:
const int* b = &Gone::a;
then you might find you do need the definition.
See the standard, $9.4.2:
ISO 1998:
"4 If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constantinitializer which shall be an integral constant expression
(5.19). In that case, the member can appear in integral constant
expressions within its scope. The member shall still be defined in a
namespace scope if it is used in the program and the namespace scope
definition shall not contain an initializer."
Draft for c++11:
"3 If a static data member is of const effective literal type, its
declaration in the class definition can specify a constant-initializer
brace-or-equal-initializer with an initializer-clause that is an
integral constant expression. A static data member of effective
literal type can be declared in the class definition with the
constexpr specifier; if so, its declaration shall specify a
constant-initializer brace-or-equal-initializer with an
initializerclause that is an integral constant expression. In both
these cases, the member may appear in integral constant expressions.
The member shall still be defined in a namespace scope if it is used
in the program and the namespace scope definition shall not contain an
initializer."
I am not sure entirely what this covers, but I think it means that we can now use the same idiom for floating point and possibly string literals.

Why does declaring a "static const" member in a header file cause linker errors?

I have a class declaration(.h file) like so:
struct MyClass {
static const uint32_t SIZE = sizeof(MyType);
};
When linking my program together, I get linker errors for MyClass::SIZE. nm confirms that the symbol is undefined. http://forums.devshed.com/c-programming-42/linker-errors-undefined-reference-to-static-member-data-193010.html seems to address my problem, indicating that "class static objects must also be declared outside any function or class just like normal globals."
I have two questions:
Is this explanation valid for my case? If so, can you explain in a little more detail why this is true?
What's the best way to fix it? I'd like to keep this member's initialization entirely in the .h file.
Your problem may have nothing to do with someone taking the address of your variable. It could simply be the compiler opting not to use the variable as a constant expression even though it could. For example:
f(int const&);
struct X { enum { enum_val = 42 }; static int const static_mem = 42; };
f(5);
f(X::enum_val);
f(X::static_mem);
In the first two cases the compiler is required to use the input as a constant expression and the const& can be initialized with such. The last case however is different. Even though your intent is probably to use static_mem as a constant expression, and its completely legitimate to do so, the compiler is free to do otherwise and some will actually create a reference to the variable itself. This is "use" of the variable and thus you're required to have a definition of that variable somewhere in the program.
There's two ways to fix this issue:
1) Add a definition to your program.
2) Use enum instead:
struct X
{
enum { static_mem = ? };
};
The first solution is necessary if you ever do intend that taking the address of your variable be possible. Chances are though that you did not or you would have created that definition already. The later solution forces the compiler to use X::static_mem as a constant expression since enum members don't actually exist as objects in the program. Based on your last statement in your question, I'm betting this is the solution you really want.
The standard requires a definition for a static member integral constant only if its address is taken, otherwise the declaration with an initializer (what you have) is enough. That linker error message should mention which object/function takes an address of MyClass::SIZE.
Quoting myself from No definition available for static const member with initializer?
And 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 within
its scope. The member shall still be
defined in a namespace scope if it is
used in the program and the namespace
scope definition shall not contain an
initializer.
From these references we can infer ("...shall still be defined..." in 9.4.2/4) that if it's not defined then the program isn't well-formed.
#David RodrĂ­guez - dribeas points out that you must be taking the address of the static member in your program somewhere. If you can avoid taking the address then there's no need for the definition in the implementation file (alternately you aren't taking the address and have a buggy compiler). Otherwise you must have the definition.
If you've to do this:
//.h file
struct MyClass
{
static const uint32_t SIZE = sizeof(MyType); //this is declaration!
};
//.cpp file
const uint32_t MyClass::SIZE; //this is definition - necessary!
Most likely, but without any error messages, it's hard to say.
Use a static const int. You can initialize it in the header, and you don't need to declare it in the cpp.