skypjack skypjack - 9 days ago 6
C++ Question

Clang does not work properly with std::experimental::optional

It seems that clang does not work properly with

std::experimental::optional
.

Consider the following example:

#include <experimental/optional>
#include <iostream>

struct Foo { int bar; };

int main() {
Foo foo;
std::experimental::optional<Foo> opt = foo;
opt.value().bar = 42;
std::cout << opt.value().bar << std::endl;
}


It compiles fine with g++ version 5.3.1, but it doesn't neither with clang version 7.0.0 nor with clang version 7.0.2.

The returned error is:

Undefined symbols for architecture x86_64:
"std::experimental::bad_optional_access::~bad_optional_access()", referenced from:
_main in main-11b2dd.o
"typeinfo for std::experimental::bad_optional_access", referenced from:
_main in main-11b2dd.o
"vtable for std::experimental::bad_optional_access", referenced from:
std::experimental::bad_optional_access::bad_optional_access() in main-11b2dd.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


I didn't manage to find any issue opened in the bug report for clang.

Who is behaving properly? I guess g++ works fine, while clang seems to be bugged. Am I wrong?


EDIT1

Actually, the bug seems to be due to the definition of
bad_optional_access
, even though the problem happens while using clang.

EDIT2

No command line parameters, but
-std=c++14
.

Tests performed with clang on osx, it compiles fine (so
optional
is freely available) as far as you don't use the
value
member method.

That means that it compiles and links using:

opt->bar


Instead of:

opt.value().bar

Answer

Your code looks perfectly fine, opt.value() should return a reference to the contained value assuming it is engaged or throw an exception. We can look at one of the older proposals which has more examples than the later ones and it includes the following paragraph:

Using the indirection operator for a disengaged object is an undefined behavior. This behavior offers maximum runtime performance. In addition to indirection operator, we provide member function value that returns a reference to to the contained value if one exists or throws an exception (derived from logic_error) otherwise

and if look at the latest proposal it describes value() as:

constexpr T const& optional<T>::value() const;
T& optional<T>::value();

Returns:

*val, if bool(*this).

Throws:

bad_optional_access if !*this.

Remarks:

The first function shall be a constexpr function.

and provides a sample implementation of value:

constexpr T const& value()
{
    return *this ? storage_.value_ : (throw bad_optional_access(""), storage_.value_);
}

In your case opt is engaged and if it was not it should just throw, we would not be invoking undefined behavior.

Note, this compiles on the last several versions of clang on Wandbox(see it live).

So as Petesh suggests this could be intentional on your platform but the only way to confirm that would be to file a bug report.

Also note as the proposal notes there is also a reference implementation on github which may be a short-term option.

Comments