Clang vs. GCC, когда static_cast'ing для типа только для перемещения - PullRequest
0 голосов
/ 20 мая 2018

Рассмотрим следующий простой класс только для перемещения:

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

Теперь давайте создадим оболочку:

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

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

  private:
    T _payload;
};

И тест:

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

Clang-6.0 доволен этим кодом, если скомпилирован с -std=c++14 или выше.GCC-8.1, однако, выдает следующую ошибку:

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

Вот ссылка на проводник компилятора , чтобы попробовать его.

Так что мой вопрос: кто прав, а ктоне так?

1 Ответ

0 голосов
/ 20 мая 2018

Упрощенный пример:

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 на godbolt.org


Прежде всего, давайте посмотрим, что это значитдля оператора преобразования должно быть explicit:

Функция преобразования может быть явной, и в этом случае она рассматривается только как определяемое пользователем преобразование для прямой инициализации .В противном случае определяемые пользователем преобразования не ограничиваются использованием в присваиваниях и инициализациях.

Считается ли static_cast прямой инициализацией ?

инициализация, которая происходит в формах

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

, а также в новых выражениях, static_cast выражениях, функциональных преобразованиях типов нотации, mem-инициализаторах и форме фигурных скобок init-спискаусловие называется прямая инициализация .


Поскольку static_cast равно прямая инициализация , не имеет значения, является ли оператор преобразованияотмечен explicit или нет.Однако удаление explicit приводит к компиляции кода на g ++ и clang ++ : живой пример на godbolt.org .

Это заставляет меня поверить, что это ошибка g ++ , так как explicit имеет значение ... когда этого не должно быть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...