Is there any way to emulate compile-time double constant with MSVS2015? - c++

I am aware MSVS2013 (even the CTP) cannot handle static constexpr double data members, as confirmed in this question.
Now, I hoped the MSVS2015 Preview would allow me to at least use this simple construct, but alas, I get the same error. So the logical next question is: is there any way to define a compile-time double constant with MSVC2015?
Example:
template<typename T>
struct my_constant
{
static constexpr const T value = 42;
}
This gives the error:
error C2864: 'my_constant<double>::value': a static data member with an in-class initializer must have non-volatile const integral type
Which is C++03 mumbo-jumbo.

If the compiler accepts a constexpr member function
static constexpr T value() {return 42;}
then that should give you a compile-time constant.
DISCLAIMER: I never use this compiler, so can't test this.

Related

static_assert fails while using constinit const. Confusion in constinit, constinit const, constexpr, const, nonconst variables

I have a question about compile time functions. I understand that static_assert should work only with types, that can be evaluated/computed at compile time. So it does not work with std::string (yet, no support in gcc10 for constexpr std::string) but will work with std::array(when I know size at compile time). I am watching C++ Weekly from Jason Turner, so this snippet is from this episode https://www.youtube.com/watch?v=INn3xa4pMfg.
The code is here: https://godbolt.org/z/e3WPTP
#include <array>
#include <algorithm>
template<typename Key, typename Value, std::size_t Size>
struct Map final
{
std::array<std::pair<Key, Value>, Size> _data;
[[nodiscard]] constexpr Value getMappedKey(const Key& aKey) const
{
const auto mapIterator = std::ranges::find_if(_data, [&aKey](const auto& pair){ return pair.first == aKey;});
if(mapIterator != _data.end())
{
return mapIterator->second;
}
else
{
throw std::out_of_range("Key is not in the map");
}
}
};
enum class OurEnum
{
OUR_VALUE,
OUR_VALUE2,
OUR_VALUE3
};
enum class TheirEnum
{
THEIR_VALUE,
THEIR_VALUE2,
THEIR_VALUE3
};
// This Fails non constant variable of course
/*
Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// This fails, it is const, but this does not guarentee that it will be created in compile time
/*
const Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// This works
/*
constexpr Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
//How come this does not work? Oh i see, missing const because constinit does not apply constness
/*
constinit Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// Okay, I added const specifier but still this makes static_assert fail because of non-constant condition
// Why?
constinit const Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
int main()
{
static_assert(enumsConverter.getMappedKey(OurEnum::OUR_VALUE) == TheirEnum::THEIR_VALUE);
}
I was playing with this sample and find out, that the static_assert does not work with constinit const initialized map. I commented out every possibility and I would like to explain them.
Map is initialized as non-const variable. I understand that this will not work, it is not constant variable nor compile time initialized
Map is initialized as const variable. This will not work either, even though the variable is constant, it is not guaranteed that it will be created at compile time.
Map is initialized as constexpr variable. This guarantee that the variable will be initialized at compile time. Also it implies constness, so we have compile time const variable. This works correctly. (https://en.cppreference.com/w/cpp/language/constexpr)
Map is initialized as constinit varibale. Now, constinit guarantees, that the expression is zero-intiialized or constant initialized. I initialize with constant so according this variable should be known at compile time (Sets the initial values of the static variables to a compile-time constant. - https://en.cppreference.com/w/cpp/language/constant_initialization) But it does not implies constness, so we have compile-time non-const variable, this static_assert can not work.
Map is initialized as constinit const variable. Now we have compile-time constant variable but static_assert refuses to work. static_assert needs contextually converted constant expression of type bool (https://en.cppreference.com/w/cpp/language/static_assert) which is A converted constant expression of type T is an expression implicitly converted to type T, where the converted expression is a constant expression. Why this does not work?
According to cppInsights, the generated code by compiler is same as for constinit const and constexpr.
Map is initialized as constinit const variable. Now we have compile-time constant variable but static_assert refuses to work
The second claim does not follow from the first. We do not have a compile-time constant variable, therefore the static_assert does not work.
constinit does not make your variable a constexpr variable, it only guarantees that you have constant initialization (hence the name constinit). Indeed, constinit does not even imply const:
constinit std::mutex m;
is a valid and motivating use for constinit, and still allows me to lock and unlock m.
The only way to have a constexpr variable is to declare your variable constexpr (with an unfortunate legacy carve out for integral types declared const, which doesn't apply here). If you want to have a constexpr map, you need to declare your map constexpr.
You are trying to address things from the wrong perspective. You see a variable declared as constinit const. You think that, because the object is non-modifiable, and because it is initialized by a constant expression, that this means that the object is a constant expression.
It's not.
Is its value knowable by the compiler? Absolutely. But that's not how "constant expression" is defined.
Something is a constant expression because the standard says that it is. A variable declared constinit is not a constant expression because the rules don't say that it is. A variable declared const is not a constant expression because the rules don't say that it is (except for certain cases of integers, which predate constexpr). And there's no special rule for the use of both of these markers.
A variable is a constant expression if it is declared constexpr (or one of those const integer exceptions). And only constant expressions can appear in static_assert.
That's the rule.
And there's no reason to have a special case of using constinit const because if you wanted a constant expression... you could have just written constexpr. After all, you might be in some template code where someone gave you a T that just so happens to be const, and you create a constinit T variable somewhere. You didn't ask it to be a constant expression; you just wanted a variable that was statically initialized. That the type just so happened to be const is just happenstance.
Now sure, the compiler is free to do all kinds of special optimizations with this knowledge. But this isn't about what the compiler is allowed to do; it's about what the language means. And if you wanted special meaning from that declaration, you should have said it correctly.
Map is initialized as constinit const variable. ... but static_assert refuses to work. ... Why this does not work?
As you have observed, static_assert needs the expression to be known at compile time.
However, const only implies logical constness, and does not imply that the value is known at compile time (ignoring the case of const integral values initialized with constant expressions).
Similarly, constinit only implies static initialization; again, this does not imply that the value is known at compile time.
From the phrasing of your question, I guess you are expecting that:
const + constinit --> constexpr
But that's not the case. If you want the Map to be usable at compile time (i.e. inside a static_assert, you'll need to make it constexpr).

MSVC compiler fatal error C1001 using pointer to method

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.

Non-constexpr variable sometimes usable in a constexpr context?

Take a look at the following code example:
template<bool val>
struct test {
static const int value_a = val;
const int value_b = val;
constexpr int get_value_a() const noexcept { return value_a; }
constexpr int get_value_b() const noexcept { return value_b; }
};
int main(int argc, char** argv) {
auto t = test<true>{};
static_assert(t.value_a);
// static_assert(t.value_b);
static_assert(t.get_value_a());
// static_assert(t.get_value_b());
}
Both gcc and clang agree that this should compile, but including any of the commented out static asserts makes it invalid. For example, gcc would then produce these error messages:
error: non-constant condition for static assertion
error: the value of ‘t’ is not usable in a constant expression
note: ‘t’ was not declared ‘constexpr’
This makes perfect sense to me and is exactly what I would have thought. But I don't really know why the other two static asserts compile in the first place. What is the relevant paragraph from the standard that allows this?
In particular, how is this formalized? Is there a clearly defined difference between just using a variable, versus actually accessing its runtime value (which then would be the only forbidden thing in a constexpr context)?
It's just the rules. Before constexpr, const variables initialised with constant expressions could be used as constant expressions themselves (Also for some compatibility with C)
From the standard [expr.const]/3:
A variable is usable in constant expressions after its initializing declaration is encountered if [...] it is a constant-initialized variable [...] of const-qualified integral or enumeration type.
This wouldn't extend to const auto t = test<true>{} because test<true> is not an integral type (You would need to have constexpr auto t = test<true>{}, as expected, following the rules of the rest of that paragraph)
In particular, how is this formalized?
http://eel.is/c++draft/expr.const#4.1
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
this ([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of e;
Access to non-static members evaluates the this pointer. Access to a static member does not.

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.

How is in-class static const initialization of float different from int in C++?

I have a class with static const members that I'm initializing inside the class declaration:
#include <iostream>
class Foo
{
public:
static const int i = 9;
static const float f = 2.9999;
};
int main()
{
std::cout << Foo::i << std::endl;
std::cout << Foo::f << std::endl;
return 0;
}
When compiled with GCC 4.8.2 with option --std=c++11, it gives this compile error:
foo.cpp:7:32: error: ‘constexpr’ needed for in-class initialization of static data member ‘const float Foo::f’ of non-integral type [-fpermissive]
static const float f = 2.9999;
^
As the message indicates, the error goes away if the line is changed to static constexpr float f = 2.9999;.
Why should the in-class static const initialization of a floating-point variable be any different from a integral variable? Aren't they both just a value of certain size (number of bytes) that is copied over (like a macro) or referred to using a pointer?
Some older answers to similar (not the same) questions on SO indicate that this is because floating point expressions might give different results between the compiled machine and the execution machine (assuming a cross-compilation scenario).
However:
the above code assigns a value directly, there is no arithmetic operation that needs to be performed to compute a value
there might be different results for integral expressions too since its underflow and overflow results are not unambiguously defined across different architectures.
Finally, what magic does constexpr do here that const does not? Why doesn't the language just do what constexpr does when const is used? I mean, why another keyword when the following statements work fine as C++ code outside a class anyway:
const int i = 9;
const float f = 2.9999;
It's just a limitation of the language, and one that has been addressed by the introduction of generalized constant expressions.
Since the original C++, only static class member constants of integral type can be initialized inline; this is the is same type restriction as for non-type template parameters. So you can combine the two like this:
struct MyTrait { static const int value = 10; };
template <int N> struct Foo;
Foo<MyTrait::value> foo;
In this usage, the static constant is not odr-used and no definition is required. I'm speculating, but I can imagine that this kind of use was the primary intention of allowing inline initialization. For all other types, you would presumably want to have a definition anyway, so you might as well put the initializer in the definition.
This isn't an excuse, of course, and I suppose the introduction of constexpr seeks to rectify this original narrow-mindedness.