неявное копирование структуры с конструкторами declard и forward-forwarding

Я хотел бы, чтобы структура инициализировала своего члена с пересылкой аргументов. Это компилируется и работает нормально, за исключением случаев, когда я объявляю деструктор и пытаюсь вернуть структуру из функции (что, я считаю, требует конструктора копирования).

#include <utility>

struct Foo
{
int val;

Foo(int val) : val(val)
{
}
};

struct FooContainer
{
Foo member;

template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}

~FooContainer() {}
};

FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}

int main() {}

Ошибка компилятора:

example.cc: In constructor ‘FooContainer::FooContainer(Args&& ...) [with Args = FooContainer&]’:
example.cc:27:   instantiated from here
example.cc:18: error: no matching function for call to ‘Foo::Foo(FooContainer&)’
example.cc:7: note: candidates are: Foo::Foo(int)
example.cc:4: note:                 Foo::Foo(const Foo&)

Похоже, что он пытается сгенерировать конструктор копирования для FooContainer но терпит неудачу, потому что у него нет способа инициализировать Foo. Тем не менее, если я удалю FooContainer конструктор или деструктор, он прекрасно компилируется. * Почему он это делает?

*на http://cpp.sh/ с GCC 4.9.2 в любом случае. G ++ 4.4.3 в Ubuntu выдает ту же ошибку, даже если деструктор не объявлен.

0

Решение

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

Удалите это, и проблема исчезнет (вы все равно хотите использовать правило нуля, верно?)

Если у вас должен быть деструктор, и вы по какой-то причине не можете его реорганизовать, то замена конструктора перемещения (который вы неявно удалили, предоставив деструктор) также решит его.

Решение 1 — использовать правило 0:

#include <utility>

struct Foo
{
int val;

Foo(int val) : val(val)
{
}
};

struct FooContainer
{
Foo member;

template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}

//    ~FooContainer() {}
};

FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}

int main() {}

Решение 2 — используйте правило 5:

#include <utility>

struct Foo
{
int val;

Foo(int val) : val(val)
{
}
};

struct FooContainer
{
Foo member;

template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}

FooContainer(const FooContainer&) = default;
FooContainer(FooContainer&&) = default;
FooContainer& operator=(const FooContainer&) = default;
FooContainer& operator=(FooContainer&&) = default;

~FooContainer() {}
};

FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}

int main() {}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]