MSVC compiler fatal error C1001 using pointer to method - c++

While writing a custom reflection library I encountered a strange compiler behavior. However I was able to reproduce the problem with a much simplified code. Here is:
#include <iostream>
class OtherBase{};
class Base{};
/* Used only as a test class to verify if the reflection API works properly*/
class Derived : Base, OtherBase
{
public:
void Printer()
{
std::cout << "Derived::Printer() has been called" << std::endl;
}
};
/*Descriptor class that basically incapsulate the address of Derived::Printer method*/
struct ClassDescriptor
{
using type = Derived;
struct FuncDescriptor
{
static constexpr const auto member_address{ &type::Printer };
};
};
int main()
{
Derived derived;
auto address{ &Derived::Printer };
(derived.*address)(); // -> OK it compiles fine using the local variable address
(derived.*ClassDescriptor::FuncDescriptor::member_address)(); // -> BROKEN using the address from the descriptor class cause fatal error C1001 !
}
While trying debugging this problem I noticed that:
It happen only if Derived has multiple inheritance.
If I swap static constexpr const auto member_address{ &type::Printer } with inline static const auto member_address{ &type::Printer } it works.
Is it just a compiler bug, or I'm doing something wrong ?
Can I solve this problem while keeping the constexpr ?
Please note that I'm using MSVC 2017 with the compiler version 19.16.27024.1
All compiler options are default except for /std:c++17 enabled.
I know that updating (and surely i'll do it) the compiler version to the last one will probably solve the issue, but for now I would like to understand more about this problem.

About C1001, Microsoft Developer Network suggests that you remove some optimizations in your code: Fatal Error C1001. Once you've worked out which optimization is causing the issue, you can use a #pragma to disable that optimization in just that area:
// Disable the optimization
#pragma optimize( "", off )
...
// Re-enable any previous optimization
#pragma optimize( "", on )
Also, a fix for this issue has been released by Microsoft. You could install the most recent release.
const and constexpr:
const declares an object as constant. This implies a guarantee that once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization.
constexpr declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr is not the only way to do this.
When applied to functions the basic difference is this:
const can only be used for non-static member functions, not functions in general. It gives a guarantee that the member function does not modify any of the non-static data members.
constexpr can be used with both member and non-member functions, as well as constructors. It declares the function fit for use in constant expressions. The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly:
The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single return statement is allowed. In the case of a constructor, only an initialization list, typedefs, and static assert are allowed. (= default and = delete are allowed, too, though.)
As of C++14, the rules are more relaxed, what is allowed since then inside a constexpr function: asm declaration, a goto statement, a statement with a label other than case and default, try-block, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the definition of a variable for which no initialization is performed.
The arguments and the return type must be literal types (i.e., generally speaking, very simple types, typically scalars or aggregates)
When can I / should I use both, const and constexpr together?
A. In object declarations. This is never necessary when both keywords refer to the same object to be declared. constexpr implies const.
constexpr const int N = 5;
is the same as
constexpr int N = 5;
However, note that there may be situations when the keywords each refer to different parts of the declaration:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}
Here, NP is declared as an address constant-expression, i.e. a pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both constexpr and const are required: constexpr always refers to the expression being declared (here NP), while const refers to int (it declares a pointer-to-const). Removing the const would render the expression illegal (because (a) a pointer to a non-const object cannot be a constant expression, and (b) &N is in-fact a pointer-to-constant).
B. In member function declarations. In C++11, constexpr implies const, while in C++14 and C++17 that is not the case. A member function declared under C++11 as
constexpr void f();
needs to be declared as
constexpr void f() const;
under C++14 in order to still be usable as a const function.
You could refer to this link for more details.

Related

Is reduction of `constexpr` object lifetime legal in C++?

For ordinary objects (even for const ones), it is permissible to end their lifetime by explicitly calling the destructor. Later, for example, the program can start another object lifetime in the same memory location using placement new.
But is it legal to call the destructor of a constexpr object? Can it result in some useful or at least well-formed program?
It is easy to imagine the opposite situation:
struct A{
int v = 0;
constexpr void foo() { v ? throw 1 : ++v; }
constexpr ~A() { foo(); }
};
constexpr A y;
int main() { y.~A(); y.~A(); }
This (most probably ill-formed) program is accepted by all compilers without any single warning: https://gcc.godbolt.org/z/aqMbfjxKT
And in Clang it finished by throwing an exception from constexpr destructor of A.
[dcl.constexpr] A constexpr specifier used in an object declaration declares the object as const.
You can do with such an object whatever you can do with any other const object. constexpr, apart from implying constness of the declared object, doesn't seem to affect anything about the object itself. It only affects static properties of the program, that is, which expressions are constant expressions, which template instantiations are valid, etc. There are no special provisions for run-time behaviour of objects declared with the constexpr specifier.
The Standard uses phrases similar to "constexpr object" a couple of times but it seems to be a misnomer. In my opinion it should have referred to constexpr variables instead. There should be no such thing as "constexpr objects" (like there are no inline objects), only constexpr variables (like there are inline variables). After all, constexpr is a decl-specifier, like inline. The objects that these variables refer to are just const.

C++11 - Can't define constexpr literal using constexpr function?

I've run into what seems a counterintuitive error, namely, the inability to assign the value of a constexpr function to a constexpr literal (hope I'm using the language right). Here's the example:
class MyClass {
public:
static constexpr int FooValue(int n) { return n + 5; }
static constexpr int Foo5 = FooValue(5); // compiler error
static constexpr int Foo5Alt(void) { return FooValue(5); } // OK
};
In GCC 4.8.4, Foo5 is flagged for field initializer is not constant. Found this thread suggesting that the older version of GCC might be the culprit. So I plugged it into Coliru (GCC 6.2.0) and got the error 'static constexpr int MyClass::FooValue(int)' called in a constant expression before its definition is complete. I added Foo5Alt() which returns its value as a constexpr function rather than literal, and that compiles fine.
I guess I'm not following why FooValue(5) can't be used as the initializer for Foo5. The definition for FooValue(int n) is complete, isn't it? { return n + 5; } is the entire definition. constexpr denotes an expression that can be fully evaluated at compile time, so why can it not be used to define the return value of a constexpr literal?
What subtlety of C++ am I missing?
In C++, inline definitions of member functions for a class are only parsed after the declaration of the class is complete.
So even though the compiler "knows" about MyClass::FooValue(int), it hasn't "seen" its definition yet, and hence it can't be used in a constexpr expression.
A general workaround for this is to stick to constexpr member functions, or declare constexpr constants outside the class.
According to the standard, MyClass is considered an incomplete type when you try to invoke FooValue to initialize Foo5. Therefore, you cannot use its members as you did.
The type is considered a completely-defined object type (or complete type) at the closing }.
On the other side, the class is regarded as complete within function bodies. That's why Foo5Alt compiles just fine.
See [class.mem]/6 for further details.

trouble with static const integral member declaration [duplicate]

I ran into an interesting issue today. Consider this simple example:
template <typename T>
void foo(const T & a) { /* code */ }
// This would also fail
// void foo(const int & a) { /* code */ }
class Bar
{
public:
static const int kConst = 1;
void func()
{
foo(kConst); // This is the important line
}
};
int main()
{
Bar b;
b.func();
}
When compiling I get an error:
Undefined reference to 'Bar::kConst'
Now, I'm pretty sure that this is because the static const int is not defined anywhere, which is intentional because according to my understanding the compiler should be able to make the replacement at compile-time and not need a definition. However, since the function takes a const int & parameter, it seems to be not making the substitution, and instead preferring a reference. I can resolve this issue by making the following change:
foo(static_cast<int>(kConst));
I believe this is now forcing the compiler to make a temporary int, and then pass a reference to that, which it can successfully do at compile time.
I was wondering if this was intentional, or am I expecting too much from gcc to be able to handle this case? Or is this something I shouldn't be doing for some reason?
It's intentional, 9.4.2/4 says:
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. The
member shall still be defined in a
namespace scope if it is used in the
program
When you pass the static data member by const reference, you "use" it, 3.2/2:
An expression is potentially evaluated
unless it appears where an integral
constant expression is required (see
5.19), is the operand of the sizeof operator (5.3.3), or is the operand of
the typeid operator and the expression
does not designate an lvalue of
polymorphic class type (5.2.8). An
object or non-overloaded function is
used if its name appears in a
potentially-evaluated expression.
So in fact, you "use" it when you pass it by value too, or in a static_cast. It's just that GCC has let you off the hook in one case but not the other.
[Edit: gcc is applying the rules from C++0x drafts: "A variable or non-overloaded function whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.". The static cast performs lvalue-rvalue conversion immediately, so in C++0x it's not "used".]
The practical problem with the const reference is that foo is within its rights to take the address of its argument, and compare it for example with the address of the argument from another call, stored in a global. Since a static data member is a unique object, this means if you call foo(kConst) from two different TUs, then the address of the object passed must be the same in each case. AFAIK GCC can't arrange that unless the object is defined in one (and only one) TU.
OK, so in this case foo is a template, hence the definition is visible in all TUs, so perhaps the compiler could in theory rule out the risk that it does anything with the address. But in general you certainly shouldn't be taking addresses of or references to non-existent objects ;-)
If you're writing static const variable with initializer inside class declaration it's just like as if you've written
class Bar
{
enum { kConst = 1 };
}
and GCC will treat it the same way, meaning that it does not have an address.
The correct code should be
class Bar
{
static const int kConst;
}
const int Bar::kConst = 1;
This is a really valid case. Especially because foo could be a function from the STL like std::count which takes a const T& as its third argument.
I spent much time trying to understand why the linker had problems with such a basic code.
The error message
Undefined reference to 'Bar::kConst'
tells us that the linker cannot find a symbol.
$nm -C main.o
0000000000000000 T main
0000000000000000 W void foo<int>(int const&)
0000000000000000 W Bar::func()
0000000000000000 U Bar::kConst
We can see from the 'U' that Bar::kConst is undefined. Hence, when the linker tries to do its job, it has to find the symbol. But you only declare kConst and don't define it.
The solution in C++ is also to define it as follows:
template <typename T>
void foo(const T & a) { /* code */ }
class Bar
{
public:
static const int kConst = 1;
void func()
{
foo(kConst); // This is the important line
}
};
const int Bar::kConst; // Definition <--FIX
int main()
{
Bar b;
b.func();
}
Then, you can see that the compiler will put the definition in the generated object file:
$nm -C main.o
0000000000000000 T main
0000000000000000 W void foo<int>(int const&)
0000000000000000 W Bar::func()
0000000000000000 R Bar::kConst
Now, you can see the 'R' saying that it is defined in the data section.
The proper way in C++17 would be to simply make the variable constexpr:
static constexpr int kConst = 1;
constexpr static data member are implicitly inline.
You can also replace it by a constexpr member function:
class Bar
{
static constexpr int kConst() { return 1; };
};
g++ version 4.3.4 accepts this code (see this link). But g++ version 4.4.0 rejects it.
I think this artefact of C++ means that any time that Bar::kConst is referred to, its literal value is used instead.
This means that in practise there is no variable to make a reference point to.
You may have to do this:
void func()
{
int k = kConst;
foo(k);
}
Simple trick: use + before the kConst passed down the function. This will prevent the constant from being taken a reference from, and this way the code will not generate a linker request to the constant object, but it will go on with the compiler-time constant value instead.
I experienced the same problem as mentioned by Cloderic (static const in a ternary operator: r = s ? kConst1 : kConst2), but it only complained after turning off compiler optimization (-O0 instead of -Os). Happened on gcc-none-eabi 4.8.5.

Does in class member initialization takes place at compile time or run-time?

In C++11 a new feature was introduced where the programmer can initialize class member variables inside class's definition, see code below:
struct foo
{
int size = 3;
int id = 1;
int type = 2;
unsigned char data[3] = {'1', '2', '3'};
};
Is this initialization takes place during compile time or this feature is just syntactic sugar and member variables are initialized in the default constructor?
First of all yes, as stated before, it is syntactic sugar. But since the rules can be too much to remember, here's a logical experiment to help you figure out what happens in compile time and what not
You have your c++11 class that features in class initializers
struct foo { int size = 3; };
And another class that will help us with our experiment
template<int N>
struct experiment { enum { val = N }; };
Let our hypothesis H0 be that initialization does happen in compile time, then we could write
foo a;
experiment<a.size> b;
No luck, we fail to compile. One could argue that failure is due to foo::size being non constant so lets try with
struct foo { const int size = 3; }; // constexpr instead of const would fail as well
Again, as gcc informs us
the value of ‘a’ is not usable in a constant expression
experiment b;
or (more clearly) visual studio 2013 tells us
error C2975: 'N' : invalid template argument for 'example', expected compile-time constant expression
So, we have to discard H0 and deduce that initialization does not happen in compile time.
What would it take to happen in compile time
There is an old syntax that does the trick
struct foo { static const int size = 3; };
Now this compiles but beware this is (technically and logically) no longer in class initialization.
I had to lie for a little to make a point, but to expose the whole truth now : Message errors imply that a is the real problem. You see, since you have an instance for an object (Daniel Frey also mentions this) memory (for members) has to be initialized (at runtime). If the member was (const) static, as in the final example, then it's not part of the subobjects of a(ny) class and you can have your initialization at compile time.
In-class initialisers for member-variables are syntactic sugar for writing them in the constructor initialiser list, unless there's an explicit initialiser already there, in which case they are ignored.
In-class initialisers of static const members are for constant literals, a definition is still needed (though without initialiser).
C++ has the "as if"-rule from C, so anything resulting in the prescribed observed behavior is allowed.
Specifically, that means static objects may be initialised at compile-time.
It's just syntactic sugar. Also consider that an instance usually means memory which has to be initialized with the correct values. Just because these values are provided with a different syntax does not change the fact that the memory needs to be initialized - which happens at run-time.
Its essentially syntactic sugar for a user provided constructor which initializes the values. You are providing default values for data members. When you ask whether this happens at compile time or run time, the answer depends on the context its used in.
Hopefully, these examples will help. Try them in http://gcc.godbolt.org and see the dissassembly and compilation errors.
struct S { int size = 3; };
//s's data members are compile time constants
constexpr S s = {};
//r's data members are run time constants
const S r = {};
//rr's data members are run time constants,
//but we don't know the values in this translation unit
extern const S rr;
template <int X> class Foo {};
//Ok, s.size is a compile time expression
Foo<s.size> f;
//Error, r.size is not a compile time expression
Foo<r.size> g;
//Compile time expression, this is same as return 3;
int foo() { return s.size; }
//This also works
constexpr int cfoo() { return s.size; }
//Compiler will optimize this to return 3; because r.size is const.
int bar() { return r.size; }
//Compiler cannot optimize, because we don't know the value of rr.size
//This will have to read the value of rr.size from memory.
int baz() { return rr.size; }
As others have shown, static data members (and global variables, same thing essentially) for primitive types such as ints and floats have some weird rules where they can be const but still be used in compile time contexts as if they were constexpr. This is for backwards compatibility with C and the lack of the constexpr feature in the past. Its unfortunate now because it just makes understanding constexpr and what differentiates run time expressions from compile time expressions more confusing.
Having int size = 3; is exactly equivalent to having int size; and then each constructor that doesn't already have size in its initializer list (including compiler-generated constructors) having size(3) there.
Strictly speaking C++ doesn't have a distinction between "compile-time" and "run-time".

C++ static const access through a NULL pointer [duplicate]

This question already has answers here:
c++ access static members using null pointer
(5 answers)
Closed 8 years ago.
class Foo {
public:
static const int kType = 42;
};
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
Is this defined behavior? I read through the C++ standard but couldn't find anything about accessing a static const value like this... I've examined the assembly produced by GCC 4.2, Clang++, and Visual Studio 2010 and none of them perform a dereference of the NULL pointer, but I'd like to be sure.
You can use a pointer (or other expression) to access a static member; however, doing so through a NULL pointer unfortunately is officially undefined behavior. From 9.4/2 "Static members":
A static member s of class X may be
referred to using the qualified-id
expression X::s; it is not necessary
to use the class member access syntax
(5.2.5) to refer to a static member. A
static member may be referred to using
the class member access syntax, in
which case the object-expression is
evaluated.
Based on the example that follows:
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
The intent is to allow you to ensure that functions will be called in this scenario.
I believe that the actual value of the type is not used at all when calling
bar->kType
since kType is static, and bar is of type Foo it is the same as calling
Foo::kType
which you should really be doing anyway for clarity.
Calling bar->kType gives a compiler warning on most platforms for this reason.
Apart from the issue about accessing through the NULL pointer, there is another subtle issue in the code
$9.4.2/2 - "The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition."
$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. 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."
class Foo {
public:
static const int kType = 42;
};
int const Foo::kType;
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
So, yet one more reason for UB in the OP code.
Even if it worked it is awful code.
In serious programming you code not only for yourself, but also for others who will maintain your code.
Playing tricks like this must be avoided, because you respect your colleagues.
One consequence of this code: whether the pointer is NULL or not is even not at question, but it implies that this member kType may not be a plain non-static member of the class. Sometimes classes are big (this is evil too) and one cannot always recheck the definition of each and every variable.
Be rigorous. And call all your static members only this way:
Foo::kType
Another possibility is to follow a coding convention that let know that the member is static, for example, a s_ prefix for all classes static members:
Foo::s_kType
There is a higher rule so to speak which basically says - don't even think about compiling things that are provably not used. Advanced template programming depends on this a lot, so even if it might be a bit gray-zonish when a compiler clearly sees that the result of a construct is not used it's just going to eliminate it. Especially when it's provably safe like in this case.
You may want to try a few variants if you want - like making pointer a param of a function, result of a function, leaving a pointer uninitialized (best chance for triggering compiler complaint), doing a straight cast of 0 (best chance of being conplaint-free).