Declaring initialized C++ static variable (syntax disambiguation) - c++

Suppose I have the following C++11 code:
template<typename T>
const T& GetValueOrDefault(T* pPtr) const
{
static const T oDefaultInstance {}; // MSVC error here.
return pPtr ? *pPtr : oDefaultInstance;
}
The problem that I face is that it is not valid in MSVC 2012: MSVC 2012 doesn't support uniform initialization syntax.
To ensure that you fully understand my intentions I provide the this behavior description of the line where the error occurs:
If T is of object type the default constructor is called.
1.1. If T is a class then the variable should be constructed in-place, i.e. the statement should support non-movable and/or non-copyable classes (not relying on RVO).
If T is of scalar type the default value (zero) is used on initialization.
Such kind of behavior could be archived with the next line if I force the compiler to interpret it as a variable definition with initialization:
static const T oDefaultInstance();
My question is: how to write the line above to force the correct (for me) parse in C++2003 (or at least in MSVC 2012) ?

It seeams, this simple solution is the one you want:
template<typename T>
const T& GetValueOrDefault(T* pPtr) const
{
static T oDefaultInstance;
return pPtr ? *pPtr : oDefaultInstance;
}
Static native variable are zero-initialized, else, the default constructor is called.
For your point abour RVO, perhaps I missed something. I don't see why your default instance should be copied, as you return a reference.

Related

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.

Must I initialize function-local static consts?

I'm working with with MS Visual Studio 2017, V. 15.9.8.
I am using the excellent JetBrains ReSharper Ultimate 2019.1.2 Build 191.0.20190603.142841. It gives me a warning at the indicated location:
#include <vector>
struct T
{
std::vector<char> m;
const char *f() const
{
static const char emptyData; // ReSharper complains here
return m.size() ? &m[0] : &emptyData;
}
};
The message is
file.h: Static local variable of type 'const unsigned char' should be initialized. This is non-standard Microsoft C++ extension.
The warning disappears if emptyData is not const.
The warning is wrong since all static data, including constant static locals, are per the standard zero-initialized, right?
The warning is wrong since all static data, including constant static locals, are per the standard zero-initialized, right?
It's just slightly inaccurate. There is initial zero initialisation indeed, but after that the variable is default initialised. For char, default initialisation is no initialisation which in case of previous zero initialisation would leave the zero value intact. A pedantically correct message would be that constant objects (of this type) must not be default initialised.
The standard (latest draft says):
If a program calls for the default-initialization of an object of a const-qualified type T, T shall be a const-default-constructible class type or array thereof.
The program violates this rule and is ill-formed.
Note that until C++17 default initialisation was not allowed for any const qualified type.
I believe it's because of the const, constants variables must be initilized, if the line is const char emptyData;, you get an error for uninitialized constvariable, so I think it's not the static modifier that is causing the problem.
There is a topic about this matter that seems interesting here.
Whether it is const static char emptyData; or static const char emptyData; the error in g++2a(GNU) compiler is:
error: uninitialized 'const emptyData' [-fpermissive]

std::experimental::optional inside constexpr function

I would like to use the optional idiom inside my constexpr function to easily clarify if the variable is set or not.
What I have tried with std::experimental::optional:
constexpr bool call()
{
std::experimental::optional<bool> r;
r = true; // Error
// Similar error with:
// r = std::experimental::optional<bool>(true);
if (!r)
{
return false;
}
return *r;
}
I get the error: call to non-constexpr function - so the assignment is not possible, because this operation cannot be constexpr (Example).
But if I implement my own (very ugly, just for example) optional class, it works, because I don´t implement the assignment operator/constructor explicit.
template<typename T>
struct optional
{
bool m_Set;
T m_Data;
constexpr optional() :
m_Set(false), m_Data{}
{
}
constexpr optional(T p_Data) :
m_Set(true), m_Data(p_Data)
{
}
explicit constexpr operator bool()
{
return m_Set;
}
constexpr T operator *()
{
return m_Data;
}
};
How could I use std::..::optional in the same context with assignment inside constexpr functions?
Basically, you can't. The problem with your simple implementation is that it requires T be default-constructible - if this is not the case, this won't work.
To get around this, most implementation use either a union or some (suitably aligned) storage that can hold a T. If you are passed a T in the constructor, then all well and good, you can initialize this directly (hence it will be constexpr). However, the tradeoff here is that when calling operator=, copying the value across may require a placement-new call, which cannot be constexpr.
For example, from LLVM:
template <class _Up,
class = typename enable_if
<
is_same<typename remove_reference<_Up>::type, value_type>::value &&
is_constructible<value_type, _Up>::value &&
is_assignable<value_type&, _Up>::value
>::type
>
_LIBCPP_INLINE_VISIBILITY
optional&
operator=(_Up&& __v)
{
if (this->__engaged_)
this->__val_ = _VSTD::forward<_Up>(__v);
else
{
// Problem line is below - not engaged -> need to call
// placement new with the value passed in.
::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Up>(__v));
this->__engaged_ = true;
}
return *this;
}
As for why placement new is not constexpr, see here.
This is not possible, as explained in n3527:
Making optional a literal type
We propose that optional<T> be a literal type for trivially
destructible T's.
constexpr optional<int> oi{5};
static_assert(oi, ""); // ok
static_assert(oi != nullopt, ""); // ok
static_assert(oi == oi, ""); // ok
int array[*oi]; // ok: array of size 5
Making optional<T> a literal-type in general is impossible: the
destructor cannot be trivial because it has to execute an operation
that can be conceptually described as:
~optional() {
if (is_engaged()) destroy_contained_value();
}
It is still possible to make the destructor trivial for T's which
provide a trivial destructor themselves, and we know an efficient
implementation of such optional<T> with compile-time interface —
except for copy constructor and move constructor — is possible.
Therefore we propose that for trivially destructible T's all
optional<T>'s constructors, except for move and copy constructors,
as well as observer functions are constexpr. The sketch of reference
implementation is provided in this proposal.
In other words, it's not possible to assign a value to r even if you mark it as constexpr. You must initialize it in the same line.
How could I use std::..::optional in the same context with assignment
inside constexpr functions?
std::optional is meant to hold a value that may or may not be present. The problem with std::optional's assignment is that it must destroy the old state (call the destructor of the contained object) if any. And you cannot have a constexpr destructor.
Of cause, Trivial and integral types shouldn't have a problem, but I presume the generalization was to keep things sane. However, Assignment could have been made constexpr for trivial types. Hopefully, it will be corrected. Before then, you can role out yours. :-)
Even std::optional's constructor that you think is constexpr, is actually selectively constexpr (depending on whether the selected object constructor is). Its proposal can be found here
Unfortunately, constexpr support in std::optional is somewhat rudimentary; the constexpr-enabled member functions are just the (empty and engaged) constructors, the destructor and some observers, so you cannot alter the engaged state of an optional.
This is because there would be no way to implement assignment for non-trivially copyable types without using placement new and in-place destruction of the contained object, which is illegal within constexpr context. The same currently holds for copy and move constructors, although that may change with guaranteed copy elision, but in any case the standard marks those special member functions as non-constexpr, so you cannot use them in constexpr context.
The fix would be to make the assignment operator conditionally constexpr dependent on whether the contained type is trivial (std::is_trivial_v<T>).
There is some discussion of this issue at the reference implementation; although it's probably too late to get constexpr assignment for trivial optionals into the next version of the Standard, there's nothing preventing you writing your own (e.g. by copying and fixing the reference implementation).

The "most important const" vs. auto_ptr: Why the code does not compile?

The following code does not compile on Visual C++ 2008 nor 2010:
#include <memory>
struct A {};
std::auto_ptr<A> foo() { return std::auto_ptr<A>(new A); }
const std::auto_ptr<A> bar() { return std::auto_ptr<A>(new A); }
int main()
{
const std::auto_ptr<A> & a = foo(); // most important const
const std::auto_ptr<A> & b = bar(); // error C2558:
// class 'std::auto_ptr<_Ty>' :
// no copy constructor available or copy
// constructor is declared 'explicit'
bar(); // No error?
}
I expected the "most important const" to apply to the variable "b", and yet, it does not compile, and for some reason, the compiler asks for a copy constructor (which surprises me as there should be no copy involved here). The standalone call to bar() works fine, which means, I guess, it is really the initialization of b that is the problem.
Is this a compiler bug, or a genuine compilation error described in the standard?
(perhaps it was forbidden in C++98 and authorized in C++11?)
Note: It does compile on Visual C++ 2012, gcc 4.6, and on Solaris CC (of all compilers...), but not gcc 3.4, nor XL C)
In C++03 and C++98, when binding a const reference to an rvalue (such as a function returning by value), the implementation may bind the reference directly to the rvalue or it may make a copy of the rvalue and bind the reference to that copy. As auto_ptr's copy constructor takes a non-const reference, this second choice will only work if the rvalue returned is not const qualified but the compiler is still allowed to attempt this, even if it won't work.
In C++11, these extra copies are not allowed and the implementation must bind directly to the rvalue if a conversion isn't required.
See also here.
Pre C++11, at least, the standard required an object to be
copyable in this context. In the end, the semantics of:
T const& t = f();
, where f returns a T by value, is:
T tmp = f();
T const& t = tmp;
Which requires a copy constructor.
In the case of std::auto_ptr, the problem that you're seeing
is that the copy constructor is defined to take a non-const
reference, which means that you cannot copy a temporary. Some
compilers (e.g. Microsoft) don't enforce this, which means that
your code may work with them, but it is fundamentally illegal.
The real question is why you are using references here. You
need a local variable one way or the other; the reference only
introduces an additional layer of indirection.

Why is my constructor with non const reference as argument allowed to be called with temporary objects?

I have a sample code below.
#include<iostream>
template<typename T>
class XYZ
{
private:
T & ref;
public:
XYZ(T & arg):ref(arg)
{
}
};
class temp
{
int x;
public:
temp():x(34)
{
}
};
template<typename T>
void fun(T & arg)
{
}
int main()
{
XYZ<temp> abc(temp());
fun(temp()); //This is a compilation error in gcc while the above code is perfectly valid.
}
In the above code even though XYZ constructor takes argument as non const reference, it compiles fine while the fun function fails to compile. Is this specific to g++ compiler or c++ standard has to say something about it?
Edit:
g++ -v gives this.
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
XYZ<temp> abc(temp());
It compiles, because it is NOT a variable declaration. I'm sure you think its a variable declaration when the fact is that its a function declaration. The name of the function is abc; the function returns an object of type XYZ<temp> and takes a single (unnamed) argument which in turn is a function returning type temp and taking no argument. See these topics for detail explanation:
The Most Vexing Parse (at InformIT)
Most vexing parse (at wikipedia)
And fun(temp()) doesn't compile, because temp() creates a temporary object and a temporary object cannot be bound to non-const reference.
So the fix is this : define your function template as:
template<typename T>
void fun(const T & arg) //note the `const`
{
}
No, the standard doesn't allow to pass a temporary to non const reference. (C++0X introduced rvalue reference to allow this in some controlled cases), see 8.5.3/5 (which is too long for me to cite, the meaningful part is otherwise, the reference shall be to a non-volatile const type, but you have to read the whole list of cases to know that they don't apply here).
And
XYZ<temp> abc(temp());
is simply yet another example of the most vexing parse.