Хранение не копируемого (но подвижного) объекта в std :: pair - PullRequest
4 голосов
/ 25 июля 2011

Я пытаюсь сохранить некопируемый (но подвижный) объект внутри пары std :: следующим образом:

#include <utility>

struct S
{
    S();
private:
    S(const S&);
    S& operator=(const S&);
};

int main()
{
    std::pair<int, S> p{0, S()};
    return 0;
}

Но я получаю следующую ошибку компилятора с gcc 4.6:

In file included from include/c++/4.6.0/bits/move.h:53:0,
                 from include/c++/4.6.0/bits/stl_pair.h:60,
                 include/c++/4.6.0/utility:71,
                 from src/test.cpp:1:
include/c++/4.6.0/type_traits: In instantiation of 'const bool std::__is_convertible_helper<S, S, false>::__value':
include/c++/4.6.0/type_traits:789:12:   instantiated from 'std::is_convertible<S, S>'
src/test.cpp:13:31:   instantiated from here
src/test.cpp:7:5: error: 'S::S(const S&)' is private
include/c++/4.6.0/type_traits:782:68: error: within this context
In file included from include/c++/4.6.0/utility:71:0,
                 from src/test.cpp:1:
src/test.cpp: In constructor 'std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int, <template-parameter-2-2> = void, _T1 = int, _T2 = S]':
src/test.cpp:13:31:   instantiated from here
src/test.cpp:7:5: error: 'S::S(const S&)' is private
include/c++/4.6.0/bits/stl_pair.h:121:45: error: within this context

Кажется, компилятор пытается вызвать конструктор std::pair<_T1, _T2>::pair(_U1&&, const _T2&), что, конечно, проблематично.Разве компилятор не должен вызывать конструктор std::pair<_T1, _T2>::pair(_U1&&, _U2&&)?Что здесь происходит?

EDIT : Хорошо, я понимаю, что предоставление явного конструктора перемещения решает проблему, но я все еще немного сбит с толку.

Предположим,что я делаю класс не копируемым путем наследования от boost::noncopyable вместо объявления моего собственного конструктора частной копии.

Следующее работает нормально, предполагая, что конструктор перемещения неявно генерируется:

#include <boost/noncopyable.hpp>

struct S : boost::noncopyable
{
};

void f(S&&)
{

}

int main()
{
    f(S());
    return 0;
}

Однако с std::pair он все равно не работает:

#include <utility>
#include <boost/noncopyable.hpp>

struct S : boost::noncopyable
{
};

int main()
{
    std::pair<int, S> p{0, S()};
    return 0;
}

Ошибки:

In file included from include/c++/4.6.0/utility:71:0,
                 from src/test.cpp:1:
/include/c++/4.6.0/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int, <template-parameter-2-2> = void, _T1 = int, _T2 = S]':
src/test.cpp:16:31:   instantiated from here
/include/c++/4.6.0/bits/stl_pair.h:121:45: error: use of deleted function 'S::S(const S&)'
src/test.cpp:4:8: error: 'S::S(const S&)' is implicitly deleted because the default definition would be ill-formed:
boost/boost/noncopyable.hpp:27:7: error: 'boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable&)' is private
src/test.cpp:4:8: error: within this context

Более того, добавив конструктор по умолчанию с = default иКонструктор перемещения не помогает!

#include <utility>
#include <boost/noncopyable.hpp>

struct S : boost::noncopyable
{
    S() = default;
    S(S&&) = default;
};

int main()
{
    std::pair<int, S> p{0, S()};
    return 0;
}

Я получаю те же ошибки!Я должен явно дать определение конструктору перемещения самостоятельно, что раздражает, если в классе много членов:

#include <utility>
#include <boost/noncopyable.hpp>

struct S : boost::noncopyable
{
    S() = default;
    S(S&&) {}
};

int main()
{
    std::pair<int, S> p{0, S()};
    return 0;
}

1 Ответ

4 голосов
/ 25 июля 2011

Вам необходимо предоставить конструктор перемещения. Следующие компиляции без ошибок.

#include <utility>

struct S
{
    S() {}
    S(S&&) {}
    S& operator=(S&&) {}

    S(const S&) =delete;
    S& operator=(const S&) =delete;
};

int main()
{
    std::pair<int, S> p{0, S()};
    return 0;
}


РЕДАКТИРОВАТЬ:

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

Вот отредактированный boost::noncopyable, который определяет конструктор перемещения.

#include <utility>

namespace boost {

namespace noncopyable_  // protection from unintended ADL
{
  class noncopyable
  {
   protected:
      noncopyable() {}
      noncopyable(noncopyable&&) {};
      ~noncopyable() {}
   private:  // emphasize the following members are private
      noncopyable( const noncopyable& );
      const noncopyable& operator=( const noncopyable& );
  };
}

typedef noncopyable_::noncopyable noncopyable;

} // namespace boost

struct S : boost::noncopyable
{
    S() = default;
    S(S&&) = default;

    S& operator=(S&&) {}
};

int main()
{
    std::pair<int, S> p{0, S()};
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...