Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clang vs. GCC when static_cast'ing to a move-only type

Consider the following simple move-only class:

struct bar {
    constexpr bar() = default;
    bar(bar const&) = delete;
    bar(bar&&)      = default;
    bar& operator=(bar const&) = delete;
    bar& operator=(bar&&)      = default;
};

Now, let's create a wrapper:

template <class T>
struct box {
    constexpr box(T&& x)
        : _payload{std::move(x)}
    {}

    constexpr explicit operator T() &&
    {
        return std::move(_payload);
    }

  private:
    T _payload;
};

And a test:

int main()
{
    auto x = box<bar>{bar{}};
    auto y = static_cast<bar&&>(std::move(x));
}

Clang-6.0 is happy with this code if compiled with -std=c++14 or above. GCC-8.1 however produces the following error:

<source>: In function 'int main()':
<source>:29:45: error: invalid static_cast from type 'std::remove_reference<box<bar>&>::type' {aka 'box<bar>'} to type 'bar&&'
     auto y = static_cast<bar&&>(std::move(x));

Here's a link to compiler explorer to try it out.

So my question is, who's right and who's wrong?

like image 705
T. Westerhout Avatar asked May 19 '18 22:05

T. Westerhout


People also ask

What is the difference between Clang vs GCC vs LLVM?

With some benchmarks, it is seen that lld is faster than ld and even the newer ld-gold. Build tool – Perhaps another place where Clang Vs GCC difference comes to the forefront. GCC uses autotools and Make as its build tools whereas Clang/LLVM uses CMake as its build tool.

What is static cast in C?

Static Cast: This is the simplest type of cast which can be used. It is a compile time cast.It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). For e.g. #include <iostream>.

What are the different types of cast in C++?

2. Dynamic Cast 3. Const Cast 4. Reinterpret Cast Static Cast: This is the simplest type of cast which can be used. It is a compile time cast .It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones).

Is Clang really new code?

Insofar clang is new code, it would appear that they have squandered any opportunity for making real improvements opting instead for putting lipstick on a pig.


1 Answers

Simplified example:

struct bar 
{
    bar() = default;
    bar(bar const&) = delete;
    bar(bar&&) = default;
};

struct box 
{
    explicit operator bar() && { return bar{}; }
};

int main() { static_cast<bar&&>(box{}); }

live on godbolt.org


First of all, let's see what it means for a conversion operator to be explicit:

A conversion function may be explicit, in which case it is only considered as a user-defined conversion for direct-initialization. Otherwise, user-defined conversions are not restricted to use in assignments and initializations.

Is static_cast considered direct-initialization?

The initialization that occurs in the forms

T x(a);
T x{a};

as well as in new expressions, static_­cast expressions, functional notation type conversions, mem-initializers, and the braced-init-list form of a condition is called direct-initialization.


Since static_cast is direct-initalization, it doesn't matter whether the conversion operator is marked explicit or not. However, removing explicit makes the code compile on both g++ and clang++: live example on godbolt.org.

This makes me believe that it's a g++ bug, as explicit makes a difference here... when it shouldn't.

like image 175
Vittorio Romeo Avatar answered Sep 30 '22 08:09

Vittorio Romeo