std::experimental::optional inside constexpr function - c++

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).

Related

Why isn't there a std::construct_at in C++17?

C++17 adds std::destroy_at, but there isn't any std::construct_at counterpart. Why is that? Couldn't it be implemented as simply as the following?
template <typename T, typename... Args>
T* construct_at(void* addr, Args&&... args) {
return new (addr) T(std::forward<Args>(args)...);
}
Which would enable to avoid that not-entirely-natural placement new syntax:
auto ptr = construct_at<int>(buf, 1); // instead of 'auto ptr = new (buf) int(1);'
std::cout << *ptr;
std::destroy_at(ptr);
std::destroy_at provides two objective improvements over a direct destructor call:
It reduces redundancy:
T *ptr = new T;
//Insert 1000 lines of code here.
ptr->~T(); //What type was that again?
Sure, we'd all prefer to just wrap it in a unique_ptr and be done with it, but if that can't happen for some reason, putting T there is an element of redundancy. If we change the type to U, we now have to change the destructor call or things break. Using std::destroy_at(ptr) removes the need to change the same thing in two places.
DRY is good.
It makes this easy:
auto ptr = allocates_an_object(...);
//Insert code here
ptr->~???; //What type is that again?
If we deduced the type of the pointer, then deleting it becomes kind of hard. You can't do ptr->~decltype(ptr)(); since the C++ parser doesn't work that way. Not only that, decltype deduces the type as a pointer, so you'd need to remove a pointer indirection from the deduced type. Leading you to:
auto ptr = allocates_an_object(...);
//Insert code here
using delete_type = std::remove_pointer_t<decltype(ptr)>;
ptr->~delete_type();
And who wants to type that?
By contrast, your hypothetical std::construct_at provides no objective improvements over placement new. You have to state the type you're creating in both cases. The parameters to the constructor have to be provided in both cases. The pointer to the memory has to be provided in both cases.
So there is no need being solved by your hypothetical std::construct_at.
And it is objectively less capable than placement new. You can do this:
auto ptr1 = new(mem1) T;
auto ptr2 = new(mem2) T{};
These are different. In the first case, the object is default-initialized, which may leave it uninitialized. In the second case, the object is value-initialized.
Your hypothetical std::construct_at cannot allow you to pick which one you want. It can have code that performs default initialization if you provide no parameters, but it would then be unable to provide a version for value initialization. And it could value initialize with no parameters, but then you couldn't default initialize the object.
Note that C++20 added std::construct_at. But it did so for reasons other than consistency. They're there to support compile-time memory allocation and construction.
You can call the "replaceable" global new operators in a constant expression (so long as you haven't actually replaced it). But placement-new isn't a "replaceable" function, so you can't call it there.
Earlier versions of the proposal for constexpr allocation relied on std::allocator_traits<std::allocator<T>>::construct/destruct. They later moved to std::construct_at as the constexpr construction function, which construct would refer to.
So construct_at was added when objective improvements over placement-new could be provided.
std::construct_at has been added to C++20. The paper that did so is More constexpr containers. Presumably, this was not seen to have enough advantages over placement new in C++17, but C++20 changes things.
The purpose of the proposal that added this feature is to support constexpr memory allocations, including std::vector. This requires the ability to construct objects into allocated storage. However, just plain placement new deals in terms of void *, not T *. constexpr evaluation currently has no ability to access the raw storage, and the committee wants to keep it that way. The library function std::construct_at adds a typed interface constexpr T * construct_at(T *, Args && ...).
This also has the advantage of not requiring the user to specify the type being constructed; it is deduced from the type of the pointer. The syntax to correctly call placement new is kind of horrendous and counter-intuitive. Compare std::construct_at(ptr, args...) with ::new(static_cast<void *>(ptr)) std::decay_t<decltype(*ptr)>(args...).
There is such a thing, but not named like you might expect:
uninitialized_copy
copies a range of objects to an uninitialized area of memory
uninitialized_copy_n
(C++11)
copies a number of objects to an uninitialized area of memory
(function template)
uninitialized_fill
copies an object to an uninitialized area of memory, defined by a range
(function template)
uninitialized_fill_n
copies an object to an uninitialized area of memory, defined by a start and a count
(function template)
uninitialized_move
(C++17)
moves a range of objects to an uninitialized area of memory
(function template)
uninitialized_move_n
(C++17)
moves a number of objects to an uninitialized area of memory
(function template)
uninitialized_default_construct
(C++17)
constructs objects by default-initialization in an uninitialized area of memory, defined by a range
(function template)
uninitialized_default_construct_n
(C++17)
constructs objects by default-initialization in an uninitialized area of memory, defined by a start and a count
(function template)
uninitialized_value_construct
(C++17)
constructs objects by value-initialization in an uninitialized area of memory, defined by a range
(function template)
uninitialized_value_construct_n
(C++17)
constructs objects by value-initialization in an uninitialized area of memory, defined by a start and a count
There is std::allocator_traits::construct. There used to be one more in std::allocator, but that got removed, rationale in standards committee paper D0174R0.
I think there should be a standard construct-function.
In fact libc++ has one as an implementation detail in the file stl_construct.h.
namespace std{
...
template<typename _T1, typename... _Args>
inline void
_Construct(_T1* __p, _Args&&... __args)
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
...
}
I think is it something useful to have because it allows to make "placement new" a friend.
This is a great customization point for a move-only type that need uninitialized_copy into the default heap (from an std::initializer_list element for example.)
I have my own container library that reimplements a detail::uninitialized_copy (of a range) to use a custom detail::construct:
namespace detail{
template<typename T, typename... As>
inline void construct(T* p, As&&... as){
::new(static_cast<void*>(p)) T(std::forward<As>(as)...);
}
}
Which is declared a friend of a move-only class to allow copy only in the context of placement new.
template<class T>
class my_move_only_class{
my_move_only_class(my_move_only_class const&) = default;
friend template<class TT, class...As> friend void detail::construct(TT*, As&&...);
public:
my_move_only_class(my_move_only_class&&) = default;
...
};
construct does not seem to provide any syntactic sugar. Moreover it is less efficient than a placement new. Binding to reference arguments cause temporary materialization and extra move/copy construction:
struct heavy{
unsigned char[4096];
heavy(const heavy&);
};
heavy make_heavy(); // Return a pr-value
auto loc = ::operator new(sizeof(heavy));
// Equivalently: unsigned char loc[sizeof(heavy)];
auto p = construct<heavy>(loc,make_heavy()); // The pr-value returned by
// make_heavy is bound to the second argument,
// and then this arugment is copied in the body of construct.
auto p2 = new(loc) auto(make_heavy()); // Heavy is directly constructed at loc
//... and this is simpler to write!
Unfortunately there isn't any way to avoid these extra copy/move construction when calling a function. Forwarding is almost perfect.
On the other hand, construct_at in the library could complete the standard library vocabulary.

class constructor precedence with a variadic template constructor for a value wrapper

Today I've discovered that I don't understand the C++ constructor precedence rules.
Please, see the following template struct wrapper
template <typename T>
struct wrapper
{
T value;
wrapper (T const & v0) : value{v0}
{ std::cout << "value copy constructor" << std::endl; }
wrapper (T && v0) : value{std::move(v0)}
{ std::cout << "value move constructor" << std::endl; }
template <typename ... As>
wrapper (As && ... as) : value(std::forward<As>(as)...)
{ std::cout << "emplace constructor" << std::endl; }
wrapper (wrapper const & w0) : value{w0.value}
{ std::cout << "copy constructor" << std::endl; }
wrapper (wrapper && w0) : value{std::move(w0.value)}
{ std::cout << "move constructor" << std::endl; }
};
It's a simple template value wrapper with copy constructor (wrapper const &), a move constructor (wrapper && w0), a sort of value copy constructor (T const & v0), a sort of move constructor (T && v0) and a sort of template construct-in-place-the-value constructor (As && ... as, following the example of emplace methods for STL containers).
My intention was to use the copy or moving constructor calling with a wrapper, the value copy or move constructor passing a T object and the template emplace constructor calling with a list of values able to construct an object of type T.
But I don't obtain what I expected.
From the following code
std::string s0 {"a"};
wrapper<std::string> w0{s0}; // emplace constructor (?)
wrapper<std::string> w1{std::move(s0)}; // value move constructor
wrapper<std::string> w2{1u, 'b'}; // emplace constructor
//wrapper<std::string> w3{w0}; // compilation error (?)
wrapper<std::string> w4{std::move(w0)}; // move constructor
The w1, w2 and w4 values are constructed with value move constructor, emplace constructor and move constructor (respectively) as expected.
But w0 is constructed with emplace constructor (I was expecting value copy constructor) and w3 isn't constructed at all (compilation error) because the emplace constructor is preferred but ins't a std::string constructor that accept a wrapper<std::string> value.
First question: what am I doing wrong?
I suppose that the w0 problem it's because s0 isn't a const value, so the T const & isn't an exact match.
Indeed, if I write
std::string const s1 {"a"};
wrapper<std::string> w0{s1};
I get the value copy constructor called
Second question: what I have to do to obtain what I want?
So what I have to do to make the value copy constructor (T const &) to get the precedence over the emplace constructor (As && ...) also with not constant T values and, mostly, what I have to do to get the copy constructor (wrapper const &) take the precedence constructing w3?
There is no such thing as "constructor precedence rules," there's nothing special about constructors in terms of precedence.
The two problem cases have the same underlying rule explaining them:
wrapper<std::string> w0{s0}; // emplace constructor (?)
wrapper<std::string> w3{w0}; // compilation error (?)
For w0, we have two candidates: the value copy constructor (which takes a std::string const&) and the emplace constructor (which takes a std::string&). The latter is a better match because its reference is less cv-qualified than the value copy constructor's reference (specifically [over.ics.rank]/3). A shorter version of this is:
template <typename T> void foo(T&&); // #1
void foo(int const&); // #2
int i;
foo(i); // calls #1
Similarly, for w3, we have two candidates: the emplace constructor (which takes a wrapper&) and the copy constructor (which takes a wrapper const&). Again, because of the same rule, the emplace constructor is preferred. This leads to a compile error because value isn't actually constructible from a wrapper<std::string>.
This is why you have to be careful with forwarding references and constrain your function templates! This is Item 26 ("Avoid overloading on universal references") and Item 27 ("Familiarize yourself with alternatives to overloading on universal references") in Effective Modern C++. Bare minimum would be:
template <typename... As,
std::enable_if_t<std::is_constructible<T, As...>::value, int> = 0>
wrapper(As&&...);
This allows w3 because now there is only one candidate. The fact that w0 emplaces instead of copies shouldn't matter, the end result is the same. Really, the value copy constructor doesn't really accomplish anything anyway - you should just remove it.
I would recommend this set of constructors:
wrapper() = default;
wrapper(wrapper const&) = default;
wrapper(wrapper&&) = default;
// if you really want emplace, this way
template <typename A=T, typename... Args,
std::enable_if_t<
std::is_constructible<T, A, As...>::value &&
!std::is_same<std::decay_t<A>, wrapper>::value
, int> = 0>
wrapper(A&& a0, Args&&... args)
: value(std::forward<A>(a0), std::forward<Args>(args)...)
{ }
// otherwise, just take the sink
wrapper(T v)
: value(std::move(v))
{ }
That gets the job done with minimal fuss and confusion. Note that the emplace and sink constructors are mutually exclusive, use exactly one of them.
As OP suggested, putting my comment as an answer with some elaboration.
Due to the way overload resolution is performed and types are matched, a variadic forward-reference type of constructor will often be selected as a best match. This would happen because all const qualification will be resolved correctly and form a perfect match - for example, when binding a const reference to a non-const lvalue and such - like in your example.
One way to deal with them would be to disable (through various sfinae methods at our disposal) variadic constructor when argument list matches (albeit imperfectly) to any of other available constructors, but this is very tedious, and requires ongoing support whenever extra constructors are added.
I personally prefer a tag-based approach and use a tag type as a first argument to variadic constructor. While any tag structure would work, I tend to (lazily) steal a type from C++17 - std::in_place. The code now becomes:
template<class... ARGS>
Constructor(std::in_place_t, ARGS&&... args)
And than called as
Constructor ctr(std::in_place, /* arguments */);
Since in my experience in the calling place the nature of constructor is always known - i.e. you will always know if you intend to call forward-reference accepting constructor or not - this solution works well for me.
As said in the comment, the problem is that the variadic template constructor
takes argument by forwarding reference, so it is a better match for non const lvalue copy or const rvalue copy.
There are many way to disable it, one efficient way is to always use a tag as in_place_t as proposed by SergeyA in its answer. The other is to disable the template constructor when it matches the signature of a copy constructor as it is proposed in the famous Effective C++ books.
In this case, I prefer to declare all possible signature for copy/move constructors (and also copy/move assignment). This way, whatever new constructor I add to the class, I will not have to think about avoiding copy construction, it is short 2 line of code, easy to read and it does not pollute the interface of other constructors:
template <typename T>
struct wrapper
{
//...
wrapper (wrapper& w0) : wrapper(as_const(w0)){}
wrapper (const wrapper && w0) : wrapper(w0){}
};
NB: this solution should not be used if one plan to use it as a volatile type, or if all the following condition are fullfilled:
the object size is smaller than 16bytes (or 8 byte for MSVC ABI),
all member suboject are trivially copyable,
this wrapper is going to be passed to functions where special care is taken for the case where the argument is of a trivially copyable type and its size is lower than the previous threshold because in this case, the argument can be passed in a register (or two) by passing the argument by value!
If all these requirement are fulfilled, then you may think about implementing less maintainable (error prone -> next time one will modify the code) or client interface polluting solution!

Why is this user-defined conversion not done?

Consider:
template<typename T>
struct Prop
{
T value;
operator T() { return value; }
};
int main()
{
Prop<float> p1 { 5 };
Prop<std::vector<float>> p2 { { 1, 2, 3 } };
float f1 = p1; // Works fine
float f2_1_1 = p2.value[0]; // Works fine
float f2_1_2 = p2[0]; // Doesn't compile
return 0;
}
Why doesn't the line marked as such compile? Shouldn't it perform implicit conversion using the supplied conversion operator into std::vector<>, so that the [] can be found?
There are (many) other questions on this site that ask variations on this question, but I couldn't find one that I think applies here. Does it have to do with std::vector being a template?
Implicit conversions are not considered for objects of member function calls, including the subscript operator overload.
Consider the consequences if that were allowed: Every single time any undeclared member function is called like this, the compiler would have to figure out all the types that the object can be converted to (note that any other otherwise unrelated type could have a converting constructor), and check if that has declared the missing member function. Not to mention how confusing that would be for the reader of the code (the conversion might be obvious in your conversion operator case, but not in the converting constructor case, and as far as I know, they are not otherwise treated differently).
So is there a notationally convenient way to get Prop to behave the way I want
You would have to define a member function for each of the member function of vector that you want to pass pass through transparently. Here is the subscript operator as an example:
auto operator[](std::size_t pos) {
return value[pos];
}
auto operator[](std::size_t pos) const {
return value[pos];
}
The problem is of course that all wrapped member functions must be explicitly declared. Another problem is arguments whose type depend on T. For example, vector::operator[] uses vector::size_type, which might not be defined for all T that you might use (certainly not for float). Here we make a compromise and use std::size_t.
A less laborious way of creating such "transparent" wrapper is inheritance. A publicly inheriting template would automatically have all the member functions of the parent and be implicitly convertible to it and can be referred by pointers and references of parent type. However, the transparency of such approach is a bit problematic mainly because ~vector is not virtual.
Private inheritance allows same wrapping as your member approach, but with much nicer syntax:
template<typename T>
struct Prop : private T
{
using T::operator[];
using T::T;
};
Note that inheritance approach prevents you from using fundamental types as T. Also, it makes the implicit conversion impossible (even with conversion operator) , so you cannot use Prop as T in free functions that expect T.
PS. Note that your conversion operator returns a value, so the vector must be copied, which may be undesirable. Consider providing reference versions instead:
operator T&&()&& { return *this; }
operator T&()& { return *this; }
operator const T&() const& { return *this; }
the same way that any of the
p2.size();
p2.begin();
p2.push_back(24);
// etc.
don't make sense to compile
also
p2[0];
which is equivalent with
p2.operator[](0);
doesn't make sense to compile\
If you want this behavior (i.e. for Prop<T> to borrow T members) there is a C++ proposal by Bjarne to add the dot operator to the language. I would work the same way that operator -> works for smart pointers. AFAIR it had a lot of controversy and so I wouldn't hold my breath for it.
A bit of background for the operator dot proposal—Bjarne Stroustrup
Operator Dot (R3) - Bjarne Stroustrup, Gabriel Dos Rei
Smart References through Delegation: An Alternative to N4477's Operator Dot - Hubert Tong, Faisal Vali
Alternatives to operator dot - Bjarne Stroustrup

Why is a cast operator to std::optional ignored?

This code
#include <iostream>
#include <optional>
struct foo
{
explicit operator std::optional<int>() {
return std::optional<int>( 1 );
}
explicit operator int() {
return 2;
}
};
int main()
{
foo my_foo;
std::optional<int> my_opt( my_foo );
std::cout << "constructor: " << my_opt.value() << std::endl;
my_opt = static_cast<std::optional<int>>(my_foo);
std::cout << "static_cast: " << my_opt.value() << std::endl;
}
produces the following output
constructor: 2
static_cast: 2
in Clang 4.0.0 and in MSVC 2017 (15.3). (Let's ignore GCC for now, since it's behavior seems to be buggy in that case.)
Why is the output 2? I would expect 1. The constructors of std::optional seem to prefer casting to the inner type (int) despite the fact that a cast to the outer type (std::optional<int>) is available. Is this correct according to the C++ standard? If so, is there a reason the standard does not dictate to prefer an attempt to cast to the outer type? I would find this more reasonable and could imagine it to be implemented using enable_if and is_convertible to disable the ctor if a conversion to the outer type is possible. Otherwise every cast operator to std::optional<T> in a user class - even though it is a perfect match - would be ignored on principle if there is also one to T. I would find this quite obnoxious.
I posted a somewhat similar question yesterday but probably did not state my problem accurately, since the resulting discussion was more about the GCC bug. That's why I am asking again more explicitly here.
In case Barry's excellent answer still isn't clear, here's my version, hope it helps.
The biggest question is why isn't the user-defined conversion to optional<int> preferred in direct initialization:
std::optional<int> my_opt(my_foo);
After all, there is a constructor optional<int>(optional<int>&&) and a user-defined conversion of my_foo to optional<int>.
The reason is the template<typename U> optional(U&&) constructor template, which is supposed to activate when T (int) is constructible from U and U is neither std::in_place_t nor optional<T>, and direct-initialize T from it. And so it does, stamping out optional(foo&).
The final generated optional<int> looks something like:
class optional<int> {
. . .
int value_;
. . .
optional(optional&& rhs);
optional(foo& rhs) : value_(rhs) {}
. . .
optional(optional&&) requires a user-defined conversion whereas optional(foo&) is an exact match for my_foo. So it wins, and direct-initializes int from my_foo. Only at this point is operator int() selected as a better match to initialize an int. The result thus becomes 2.
2) In case of my_opt = static_cast<std::optional<int>>(my_foo), although it sounds like "initialize my_opt as-if it was std::optional<int>", it actually means "create a temporary std::optional<int> from my_foo and move-assign from that" as described in [expr.static.cast]/4:
If T is a reference type, the effect is the same as performing the
declaration and initializationT t(e); for some invented temporary
variable t ([dcl.init]) and then using the temporary variable as the
result of the conversion. Otherwise, the result object is
direct-initialized from e.
So it becomes:
my_opt = std::optional<int>(my_foo);
And we're back to the previous situation; my_opt is subsequently initialized from a temporary optional, already holding a 2.
The issue of overloading on forwarding references is well-known. Scott Myers in his book Effective Modern C++ in Chapter 26 talks extensively about why it is a bad idea to overload on "universal references". Such templates will tirelessly stamp out whatever the type you throw at them, which will overshadow everything and anything that is not an exact match. So I'm surprised the committee chose this route.
As to the reason why it is like this, in the proposal N3793 and in the standard until Nov 15, 2016 it was indeed
optional(const T& v);
optional(T&& v);
But then as part of LWG defect 2451 it got changed to
template <class U = T> optional(U&& v);
With the following rationale:
Code such as the following is currently ill-formed (thanks to STL for
the compelling example):
optional<string> opt_str = "meow";
This is because it would require two user-defined conversions (from
const char* to string, and from string to optional<string>) where the
language permits only one. This is likely to be a surprise and an
inconvenience for users.
optional<T> should be implicitly convertible from any U that is
implicitly convertible to T. This can be implemented as a non-explicit
constructor template optional(U&&), which is enabled via SFINAE only
if is_convertible_v<U, T> and is_constructible_v<T, U>, plus any
additional conditions needed to avoid ambiguity with other
constructors...
In the end I think it's OK that T is ranked higher than optional<T>, after all it's a rather unusual choice between something that may have a value and the value.
Performance-wise it is also beneficial to initialize from T rather than from another optional<T>. An optional is typically implemented as:
template<typename T>
struct optional {
union
{
char dummy;
T value;
};
bool has_value;
};
So initializing it from optional<T>& would look something like
optional<T>::optional(const optional<T>& rhs) {
has_value = rhs.has_value;
if (has_value) {
value = rhs.value;
}
}
Whereas initializing from T& would require less steps:
optional<T>::optional(const T& t) {
value = t;
has_value = true;
}
A static_cast is valid if there is an implicit conversion sequence from the expression to the desired type, and the resulting object is direct-initialized from the expression. So writing:
my_opt = static_cast<std::optional<int>>(my_foo);
Follows the same steps as doing:
std::optional<int> __tmp(my_foo); // direct-initialize the resulting
// object from the expression
my_opt = std::move(__tmp); // the result of the cast is a prvalue, so move
And once we get to construction, we follow the same steps as my previous answer, enumerating the constructors, which ends up selecting the constructor template, which uses operator int().

How are copy constructors used and why are they important? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
What are copy constructors?
Why do we use them? Is it necessary to call a destructor if we do?
What is a copy constructor?
Quoting the C++11 standard, §12.8/2:
“A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&,
volatile X& or const volatile X&, and either there are no other parameters or else all other parameters
have default arguments”
So there are 4 different forms. Of these the X const& form is the one most often used. This is also the form of the implicit copy constructor that is generated (if possible) if no copy constructor is declared for the class.
A copy constructor is used for copying an object to a new instance of the class. A default copy constructor performs a member-wise copy, which is different from and more safe than just copying the bits. In particular a copy constructor or move constructor is logically used for a copy initialization, an initialization using the = sign like
Some_type x = expression;
In some circumstances the compiler is allowed to assume that copying is all that a copy constructor does, regardless of what it actually does. Logically needless copy constructions can then be removed, or as the standard calls it, elided. For example, if the expression above is the number 42, then instead of using that argument to construct a temporary and copying or moving that to x, the argument may be used to initialize x directly.
However, even when that is done, so that the copy constructor is not used, if the copy constructor would have been used except for the optimization then a copy constructor must exist and be accessible.
C++11 §12.2/1:
“Even when the creation of the temporary object is unevaluated (Clause 5)
or otherwise avoided (12.8), all the semantic restrictions shall be respected as if the temporary object had
been created and later destroyed.”
Is it necessary to call a destructor?
Re “Is it necessary to call a destructor if we [use a copy constructor]? ”.
Generally no.
Destructors in C++ are called automatically when an object goes out of scope or when it's indirectly or directly destroyed via delete. The only exception is for placement new, which is a low level feature that has nothing in particular to do with copy constructors. Although placement new can involve copy construction.
A difference between C++03 and C++11 copy constructors.
To understand the difference between C++03 and C++11 regarding copy constructors you must be aware of three facts:
If a copy constructor isn’t declared, then it’s generated if possible. Hence by default every class has a copy constructor. It’s there.
Access is independent of overload resolution.
Overload resolution chooses between all member functions, regardless of whether they’re accessible or not. Then access is checked. At that point you may get an error message about calling an inaccessible function, despite an expectation that overload resolution ideally should choose only from the accessible functions…
An ordinary function (or just function) is a better match than a an instantiation of a function template with the same signature.
Here is an example of overloading resolution choosing a private member function, in spite of a public function that could be called:
File [access_versus_overload_resolution.cpp]
class C
{
public:
void foo( double );
void foo( int );
void bar( double );
private:
void bar( int );
};
int main()
{
C().foo( 42 ); // OK.
C().bar( 42 ); //! Uh oh, inaccessible.
}
And here is an example of an ordinary function trumping a template instantiation:
File [function_versus_template.cpp]
using One = char[1];
using Two = char[2];
auto foo( char const* ) -> One&;
auto foo( char const (&)[10] ) -> Two&;
auto bar( char const* ) -> One&;
template< int n >
auto bar( char const (&)[n] ) -> Two&;
#include <iostream>
auto main() -> int
{
using namespace std;
//cout << sizeof( foo( "Blah blah" ) ) << endl; //! Ambiguous
cout << sizeof( bar( "Blah blah" ) ) << endl; // "1"
}
With these facts at hand:
An inaccessible copy constructor will be chosen even if there is an accessible member function template that is just as good a match.
(As a logical consequence of the general overload resolution rules.)
In C++11, a member function template instantiation will therefore be chosen only if it is a better match than the copy constructor, if any.
But in C++03 there was a special rule that ensured that with a conforming compiler a function member template would never be used to copy an object.
Here’s the C++03 wording, §12.8/3 in that standard, where I’ve added suitable emphasis:
“A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-
qualified) X and either there are no other parameters or else all other parameters have default arguments. A
member function template is never instantiated to perform the copy of a class object to an object of its class
type.
while in C++11 the wording is subtly changed, in that standard’s §12.8/6, where again I’ve added suitable emphasis:
“A declaration of a constructor for a class Xis ill-formed if its first parameter is of type (optionally cv-qualified)
X and either there are no other parameters or else all other parameters have default arguments. A member
function template is never instantiated to produce such a constructor signature.”
I.e. no special injunction against function templates being used to copy objects in C++11.
Unfortunately for history buffs, the most readily available C++03 compiler for Windows, namely MinGW g++ of some old version such as 3.2, does not enforce the C++03 rule.
File [template_versus_cc.cpp]
class S
{
private:
S( S const& ); // No such.
public:
S() {}
template< class T >
S( T& ) {}
};
int main()
{
S sm;
S const sc;
S s1( sm ); // OK in C++11, template is better match.
S s2( sc ); //! Line 19. Copy constructor is selected, inaccessible.
}
Compiling with old g++:
[H:\dev\test\copy_construction]
> \bin\MinGW_3_1\bin\g++ --version | find "++"
g++ (GCC) 3.2.3 (mingw special 20030504-1)
[H:\dev\test\copy_construction]
> \bin\MinGW_3_1\bin\g++ -std=c++98 -pedantic template_versus_cc.cpp
template_versus_cc.cpp: In function `int main()':
template_versus_cc.cpp:4: `S::S(const S&)' is private
template_versus_cc.cpp:19: within this context
[H:\dev\test\copy_construction]
> _
By the C++03/C++98 rules the compiler should have flagged both copy initializations, at lines 18 and 19, but only flagged the latter, behaving as a C++11 compiler in this respect.
This is also what the more modern g++ 4.8.2 does, as well as Visual C++ 12.0. But a conforming C++03-compiler must diagnose both initializations.
Scott Meyers has written about this, citing two of the SO C++ Lounge dwellers as sources. Unfortunately the article yields the impressions that (1) it’s all about universal reference template arguments in C++11, and (2) there’s is no bug in g++. The former is wrong, as shown above, while the latter is literally correct. There was a bug, but as the standard has evolved, with C++11 the g++ behavior is now conforming…
Copy constructors are important for quite the same reasons as a regular constructor would be, and that is to properly initialize the constructed object. Construction is not always trivial, and it doesn't matter where do you take the data from and in what form - other object of the same class or a set of simpler arguments.
Therefore copy constructor is there to solve problems like initializing const fields, but also when you use pointers, to decide on ownership of the pointed resource. You may want to share, or duplicate the data.