Andy
Andy

Reputation: 30418

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?

Upvotes: 4

Views: 309

Answers (2)

Columbo
Columbo

Reputation: 60979

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.

Upvotes: 10

Some programmer dude
Some programmer dude

Reputation: 409166

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.

Upvotes: 5

Related Questions