Variadic template: Perfect forwarding of integer parameter to lambda

  • A+
Category:Languages

There are similar questions, but I did not find an answer that works for my problem.

Consider the following code:

#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; } 

The idea is that the class DeferredCreator creates an object only when it is really needed. I got this work e.g. for strings, but I can't figure out how to pass a simple integer into my lambda.

The error message I get is:

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. 

I already tried to use decltype( args) as template argument for std::forward<>, but that did not help.

The code is also available here: https://ideone.com/MIhMkt

 


The operator() of the closure type generated by your lambda expression is const-qualified. std::forward can attempt to move args..., which are data members of the closure. const objects cannot be moved.

You can mark your lambda as mutable:

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

This removes the implicit const qualfiier from the closure type's generated operator().

live example on wandbox.org

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: