Шаблон Variadic: совершенная пересылка целочисленного параметра в лямбду - PullRequest
0 голосов
/ 05 сентября 2018

Есть похожие вопросы, но я не нашел ответа, который подходит для моей проблемы.

Рассмотрим следующий код:

#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <utility>

class TestClass
{
public:
   TestClass( int value): mValue( value) { }
private:
   int  mValue;
};

template< typename T> class DeferredCreator
{
public:
   template< class... Args> DeferredCreator( Args&&... args):
      mpCreator( [=]() -> T*
         { return new T( std::forward< Args>( args)...);  }
      ),
      mpObject()
   { }

   T* get() {
      if (mpObject == nullptr)
         mpObject.reset( mpCreator());
      return mpObject.get();
   }
private:
   std::function< T*( void)>  mpCreator;
   std::unique_ptr< T>        mpObject;
};


int main() {
   DeferredCreator< int>  dcInt( 42);

   assert( dcInt.get() != nullptr);
   return 0;
}

Идея состоит в том, что класс DeferredCreator создает объект только тогда, когда он действительно необходим. Я получил эту работу, например для строк, но я не могу понять, как передать простое число в мою лямбду.

Я получаю сообщение об ошибке:

prog.cpp:19:26: error: no matching function for call to 'forward'
         { return new T( std::forward< Args>( args)...);  }
                         ^~~~~~~~~~~~~~~~~~~
prog.cpp:36:27: note: in instantiation of function template specialization 'DeferredCreator<int>::DeferredCreator<int>' requested here
   DeferredCreator< int>  dcInt( 42);
                          ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/move.h:76:5: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
    forward(typename std::remove_reference<_Tp>::type& __t) noexcept
    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/move.h:87:5: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
    forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
    ^
2 errors generated.

Я уже пытался использовать decltype( args) в качестве аргумента шаблона для std::forward<>, но это не помогло.

Код также доступен здесь: https://ideone.com/MIhMkt

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Значение operator() типа , сгенерированное вашим лямбда-выражением , * const -качественное. std::forward может попытаться переместить args..., которые являются членами данных замыкания. const объекты не могут быть перемещены.

Вы можете пометить свою лямбду как mutable:

  mpCreator( [=]() mutable -> T*
     { return new T( std::forward< Args>( args)...);  }
  ),

Это удаляет неявный квалификатор const из типа закрытия , сгенерированного operator().

живой пример на wandbox.org

0 голосов
/ 05 сентября 2018

args... является константой, потому что лямбда-оператор вызова неявно const. Итак, если вы сделаете вашу лямбду изменчивой, то она будет работать:

[=]() mutable -> T*
     { return new T( std::forward< Args>( args)...);  }

Причина, по которой он не работал с decltype(args), заключается в том, что сами типы не const, а просто оператор вызова.

...