Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I declare a variable using auto?

I'm getting a compile error in Visual Studio 2015 when I try to declare a variable of class, when that classes uses the PIMPL pattern.

Foo.h:

#pragma once

class Foo
{
public:
  Foo(const std::wstring& str,
      const std::vector<std::wstring>& items);
  ~Foo();

private:
  struct Impl;
  std::unique_ptr<Impl> pimpl;
};

Foo.cpp:

#include "stdafx.h"
#include "Foo.h"

struct Foo::Impl
{
public:
  Impl(const std::wstring& str,
       const std::vector<std::wstring>& items);

  std::wstring str_;
  std::vector<std::wstring> items_;
};

Foo::Foo(const std::wstring& str,
         const std::vector<std::wstring>& items)
  : pimpl(std::make_unique<Impl>(str, items))
{
}

Foo::~Foo() = default;

Foo::Impl::Impl(const std::wstring& str,
                const std::vector<std::wstring>& items)
  : str_(str),
  items_(items)
{
}

If I declare a variable of type Foo using the traditional syntax, it compiles fine:

  Foo f(L"Hello", std::vector<std::wstring>());

However, if I declare it using auto, then I get a compile error:

  auto f2 = Foo { L"Goodbye", std::vector<std::wstring>() };

error C2280: 'Foo::Foo(const Foo &)': attempting to reference a deleted function
note: compiler has generated 'Foo::Foo' here

I understand that the copy constructor for Foo should be deleted, since unique_ptr can't be copied. However, it was my understanding that when declaring variables in this way, the result would be either moved into the variable or just set the value into the variable directly.

The second line compiles fine when using Visual Studio 2013. I checked the breaking changes in Visual Studio 2015, but I didn't see anything there that would indicate why this started failing.

Am I doing something wrong, or can this syntax not be used with non-copyable types?

like image 543
Andy Avatar asked Dec 06 '22 19:12

Andy


2 Answers

The move constructor is not implicitly declared, because you have a user-declared destructor (see [class.copy]/(9.4)). However, the copy constructor is clearly deleted, since unique_ptr can't be copied.

You can explicitly declare the move constructor as defaulted.

like image 120
Columbo Avatar answered Dec 31 '22 01:12

Columbo


Because the class contains a std::unique_ptr member the compiler can't generate a copy-constructor like it would normally do, which means your declaration and initialization (which invokes the copy-constructor) will not be possible.

You could solve it by making a move constructor for your class and mark it as default.

like image 39
Some programmer dude Avatar answered Dec 31 '22 01:12

Some programmer dude