Как функция может изменить параметр, передаваемый по значению в C++?

В основном это вопрос о семантике. Я использую библиотеку Cereal для (де) сериализации в C++, и мне показался интересным ее стиль кодирования:

cereal::PortableBinaryInputArchive ar(instream);
int out;
ar(out);
// int is successfully deserialized from input stream here.

Сложность состоит в том, что я не передаю "out" по ссылке, и ar() все еще может изменить его значение. На самом деле автор просто переопределяет оператор "()". И я нашел соответствующие строки в исходных файлах.

OutputArchive & operator=( OutputArchive const & ) = delete;

  //! Serializes all passed in data
  /*! This is the primary interface for serializing data with an archive */
  template <class ... Types> inline
  ArchiveType & operator()( Types && ... args )
  {
    self->process( std::forward<Types>( args )... );
    return *self;
  }

Я в полном недоумении, особенно первая строка ("= delete") и вещи, касающиеся "std::forward( args)...". Я видел только несколько случаев, когда использовались макросы типа va_arg, и я впервые столкнулся с чем-то подобным. Кроме того, что означает "&&"? Может ли кто-нибудь пролить свет на это?

1 ответ

Решение

Я в растерянности, особенно первая строка ("= delete")

"= Delete" эффективно гарантирует, что operator= (оператор присваивания...) не может быть вызван, и что значение по умолчанию (оператор присваивания) не должно генерироваться. Это то же самое, что делает operator = private и не дает определения. Этот оператор также может использоваться для обычных функций, в этом случае его использование аналогичным образом запрещено (см. Стандарт C++ 11, раздел 8.4.3):

struct B
{
  void foo(){}
};

struct D : B
{
  void foo() = delete;
};

int main() {
    D().foo(); //Fails to compile here - deliberate!!!
    return 0;
}

Обратите внимание, что тип, для которого вызывается foo, важен. Он все еще может быть вызван для базового типа, точно так же, как он может все еще нарезаться, даже если производное присвоение запрещено (см. Пример ниже):

struct B{};

struct D : B
{
  D& operator=(const D&) = delete;    
};

int main() {
    B b;
    D d1, d2;
    b = d1; //Compiles fine - slices
    d1 = d2; //Fails to compile...
    return 0;
}

и что касается "std:: forward (args)...".

std:: forward позволяет совершенную пересылку аргументов (т. е. типы аргументов относительно значения r/l и модификаторы не изменяются (см.).

Я видел только несколько случаев, когда использовались макросы типа va_arg, и я впервые столкнулся с чем-то подобным.

template <class ... Types>
void foo( Types&& ...);

... в этом контексте упоминается как шаблоны с переменным числом (google).

Кроме того, что означает "&&"? Может ли кто-нибудь пролить свет на это?

&& обозначает либо ссылку на rvalue, либо универсальную ссылку, в зависимости от контекста. В данном случае это универсальная ссылка (здесь у Скотта Мейерса есть хорошая статья об универсальных ссылках).

РЕДАКТИРОВАТЬ: универсальные ссылки теперь правильно называются переадресацией ссылки (n4164).

Другие вопросы по тегам