std :: any для шаблона только для перемещения, где static_assert внутри copy-ctor равен ошибке компиляции, но почему? - PullRequest
0 голосов
/ 12 ноября 2019

Я не понимаю, почему шаблоны только для перемещения нельзя расширить с помощью copy-ctor, имеющего static_assert (как в коде ниже) для использования с std::any

#include <any>
#include <cassert>

namespace detail{
template<typename T=int>
struct MoveOnly
{
    MoveOnly() = default;
    MoveOnly(MoveOnly const&) {static_assert(sizeof(T)!=sizeof(T),"");}
    MoveOnly(MoveOnly &&) = default;
    MoveOnly &operator=(MoveOnly const&) {static_assert(sizeof(T)!=sizeof(T),"");}
    MoveOnly &operator=(MoveOnly &&) = default;
};
}
using MoveOnly = detail::MoveOnly<>;
static_assert(std::is_copy_constructible<MoveOnly>::value,"");

int main() {
    MoveOnly a;
    //std::any any(std::move(a)); //<- compile error
    return 0;
}

В std :: any :: any говорится для ctor # 4

Эта перегрузка участвует только в разрешении перегрузки, если ... std :: is_copy_constructible_vtrue.

Насколько я вижу, std::is_copy_constructible<MoveOnly>::value дает true, а copy-ctor никогда не вызывается. Так как же возможно, что компилятор все еще жалуется на static_assert внутри copy-ctor?

1 Ответ

1 голос
/ 12 ноября 2019

Рассмотрим следующий случай:

foo.h:

void foo(const std::any& v);

foo.cpp:

void foo(const std::any& v) {
  std::any tmp = v;
}

main.cpp:

#include "foo.h"

int main() {
    MoveOnly a;
    std::any any(std::move(a));

    foo(any);

    return 0;
}

Внутри main.cpp нет никакого способа узнать, будет ли foo() делать копию v или нет, поэтому у нас нет выбора, у есть , чтобы быть конструктором копированиядоступно на всякий случай может потребоваться его запуск.

edit: Чтобы указать что-то упомянутое в комментариях:

Ok. Так что я правильно понимаю: copy-ctor создается и static_assert запускается, потому что простой указатель указывает на copy-ctor?

По сути да. Как только указатель ссылается на функцию, эта функция должна существовать, и ее реализация вызовет генерацию кода для нее, включая оценку любого static_assert() внутри.

Единственное, что немногов вашем понимании, указатель не существует только для этого. Это происходит потому, что существует реальная возможность, что его можно использовать для вызова указанной функции. Может быть, это будет оптимизировано во время LTO, но это слишком поздно;к тому времени генерация кода заканчивается

...