Access template class parameter in default lambda argument - c++

I'm writing a simple universal pool. The template class takes a parameter in the constructor that is a factory function to instantiate objects in the pool as needed.
template<typename T>
struct Foo {
std::function <T*()> factory_;
Foo(std::function<T*()> factory): factory_(factory) {}
};
This compiles fine, but I wanted to make a default argument for the constructor using lambda:
Foo(std::function<T*()> factory = [](){return new T();} ): factory_(factory) {}
This does not compile - it says that T is unknown. Is there a way to make lambda expressions aware of class template parameters? I tried using typedef, but to no avail.

This should work as proposed, however you might have hit a bug in VC++ (it's not exactly C++11 ready yet).
As a workaround, you might try to replace your lambda by a private static method instead.
template <typename T>
class LIFOPool
{
std::function <T*()> factory_;
//...details irrelevant
static T* DefaultMake() { return new T{}; }
public:
LIFOPool(std::function<T*()> factory = DefaultMake) : factory_(factory) {}
//...details irrelevant
};

Related

Allow the caller to use any pointer type (including smart pointers) with my Builder class?

The standard way of implementing a Builder for Foo goes like this:
class Foo::Builder {
public:
Builder& setBar(bool bar);
...
Foo build() const;
};
Only when the caller tries to use this class with a smart pointer:
auto builder = std::make_shared<Foo::Builder>()->setProperty(...);
The builder cannot be used in this way, because setProperty() will return a reference to an object that will be destroyed by the time this statement completes executing. When the caller is calling build() in the same statement and the Builder class is never bound to a variable name, this doesn't matter.
However, in my application, I want to be able to do some configuration on a derived builder object, then pass it to the constructor of another class (which receives it as a pointer to a base type). I also want the caller to be able to decide the type of the pointer used. Could I do this by making Foo::Builder a template? Is there a better design pattern more suited for this? I'm open to ideas.
It isnt a class buisness to have control over what others use to point to instances. If that other class recieves some pointer to a Builder in its constructor, you can make the constructor a template:
struct OtherClass {
template <typename T>
OtherClass(T t) {
t->setProperty();
}
};
If you want to restrict T to types that have an operator-> that returns a Builder you can either wait for C++20 concepts or write a typetrait that allows you to SFINAE:
template <typename P,typename T>
struct points_to : std::false_type {};
template <typename T>
struct points_to<T*,T> : std::true_type {};
template <typename P>
struct points_to<P,std::decay_t<decltype(std::declval<P>().operator->())>> : std::true_type {};
The constructor can then require that points_to<T,Builder> via:
struct AnotherClass {
template <typename T,typename = std::enable_if_t<points_to<T,Builder>::value,void>>
AnotherClass(T t){}
};
However, error messages won't be much better than for the non restricted template above. static_assert helps to get readable error messages:
struct AnotherClass {
template <typename B>
AnotherClass(B b){
static_assert(points_to<B,Builder>::value,"b is not pointing to a Builder");
}
};
Live Example

How to store and restore the exact type of a type-erased object?

I'm sure there's a name for what I'm looking for, I just don't know it (and if I did, I'd probably find the answer already). Basically, I want to implement my own lightweight version of std::function for sports. I want to initialize it with a lambda, and later invoke it. I can wrap the lambda with my template wrapper class, nothing to it:
struct CInvokableAbstract {
virtual ~CInvokableAbstract() = default;
};
template <class InvokableObject>
struct CInvokableBasic : public CInvokableAbstract
{
CInvokableBasic(InvokableObject&& target) : _invokable(std::move(target)) {}
template <typename... Args>
typename std::result_of<decltype(&InvokableObject::operator())(Args...)>::type operator()(Args... args) const
{
return _invokable(std::forward<Args>(args)...);
}
private:
InvokableObject _invokable;
};
Now I can make my class that's semantically similar to std::function, but how can I store the exact type of the lambda in order to convert the type-erased object back to its original concrete type?
struct CInvokableDeferred
{
template <class InvokableObject>
CInvokableDeferred(InvokableObject&& target) noexcept : _invokable(std::make_unique<CInvokableBasic<InvokableObject>>(std::move(target))) {}
template <typename... Args>
void operator()(Args... args) const
{
// How can I know the original concrete type to cast this to?
static_cast<???>(_invokable.get())->(std::forward<Args>(args)...);
}
private:
std::unique_ptr<CInvokableAbstract> _invokable;
};
I can't think of any template trickery that could do that, yet we know it's possible (unless std::function uses some compiler built-ins, or otherwise is implemented internally in the compiler rather than being normal C++ code).
Note that I'm using a compiler that doesn't have full C++17 support, so I can't use e. g. auto-deduced return type.
You need to rewrite your base class as follows:
template <typename Ret, typename... Args>
class CInvokableAbstract {
virtual ~CInvokableAbstract() = default;
virtual Ret operator()(Args... args) = 0;
};
This will make your base class dependent on the signature (which it has to be in order to be usable) and provide the actual interface for the invocable object.
Note that this part of code actually has nothing to do with type-erase, it's just plain old dynamic polymorphism. It's the combination of static (CInvokableBasic template) and dynamic (CInvokableAbstract interface) polymorphisms that make type-erasure possible.

Loss of rvalue qualifier with variadic template arguments

I'm trying to write a generic factory class with automatic self-registration of types for my application.
In order to allow flexibility, this factory has a variadic template parameter for constructor arguments; i.e. it allows either default constructors or constructors requiring any number of arguments. The parameter names are fairly self-explanatory; the AbstractType is the abstract base class for the factory; the returned object will be a std::shared_ptr of this type.
This generic factory works fine and all of the tests I wrote for it were working perfectly fine, until I tried to create a factory for a specific class hierarchy containing classes (as data members) that do not permit copy construction or assignment. I tried to fix this by using an rvalue reference for the template argument; however, this does not work in the manner that I expected. Specifically, if I define the factory instance to take a constructor parameter of type A&&, this fails with an error telling me that there is no conversion from A to A&&.
In this sample, My_Abstract, Data_Context, and Other_Class are declared elsewhere. As described briefly above, the idea here is that a concrete type CT will have a constructor with the signature:
class CT {
CT(Data_Context&&, Other_Class const&);
/* ... */
};
class My_Abstract; // forward declaration
template <class ConcreteType>
using My_Factory_Registrar =
Factory_Registrar<ConcreteType, My_Abstract, Data_Context &&, Other_Class const&>;
using My_Factory =
Generic_Factory<My_Abstract, Data_Context &&, Other_Class const&>;
Perhaps I am missing something fundamental here, but when I revise the code to be:
template <class ConcreteType>
using My_Factory_Registrar =
Factory_Registrar<ConcreteType, My_Abstract, Data_Context const&, Other_Class const&>;
using My_Factory =
Generic_Factory<ConcreteType, Data_Context const&, Other_Class const&>;
Then everything compiles and works correctly. I am well aware that an r-value can be used for a const reference parameter, so I am not confused as to why this worked, as much as I am completely confused why the first code snippet did not work. It almost appears like the rvalue reference qualifier was removed in the process of variadic template expansion.
I'm not sure whether or not it will help at all in clarifying thing, but the code for the factory class itself is as follows:
template <class AbstractType, class...ConstructorArgs>
class Generic_Factory{
public:
static std::shared_ptr<AbstractType> Construct(std::string key, ConstructorArgs... arguments){
auto it = Get_Registry()->find(key);
if (it == Get_Registry()->cend())
return nullptr;
auto constructor = it->second;
return constructor(arguments...);
}
using Constructor_t = std::function<std::shared_ptr<AbstractType>(ConstructorArgs...)>;
using Registry_t = std::map< std::string, Constructor_t>;
Generic_Factory(Generic_Factory const&) = delete;
Generic_Factory& operator=(Generic_Factory const&) = delete;
protected:
Generic_Factory(){}
static Registry_t* Get_Registry();
private:
static Registry_t* _registry_;
};
template <class ConcreteType, class AbstractType, class...ConstructorArgs>
struct Factory_Registrar : private Generic_Factory<AbstractType, ConstructorArgs...>{
using Factory = Generic_Factory<AbstractType, ConstructorArgs...>;
using Constructor_t = typename Factory::Constructor_t;
public:
Factory_Registrar(std::string const& designator, Constructor_t object_constructor){
auto registry = Factory::Get_Registry();
if (registry->find(designator) == registry->cend())
registry->insert(std::make_pair(designator, object_constructor));
}
};
Thanks for your help.
Shmuel
Perfect Forwarding is intended to be used in these cases. Your code is quite long. I use a simplified version of make_unique for demonstration.
template <typename T, typename ...Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T>
{
return std::unique_ptr<T>{new T(std::forward<Args>(args)...)};
}
To be able to forward rvalue input arguments without losing type information, you need to use universal references. The prototypical example is :
template<class T>
void Forwarder(T&& t)
{
Func(std::forward<T>(t));
}
This way, there is no loss of type information and the right overload of Func gets called.
On the other hand, if the body of Forwarder called Func(t), only the lvalue overload of Func would match.

c++ template containing object using same type T

I have a class MemoryPool with the following (shortened to relevant) code:
namespace System
{
template <class T>
class MemoryPool
{
public:
// only constructor
MemoryPool(const size_t itemsToInitNow, const size_t maxItems)
: _maxItemsInMemoryPool(maxItems)
{
// initialize itemsToInitNow items immediately
for(size_t i = 0; i < itemsToInitNow; ++i) {
_container.push_back(MemoryItemSharedPointer(new MemoryItem<T>(_factory.CreateItem())));
}
}
.. other stuff
private:
.. other stuff
// private data members
AbstractFactory<T> _factory;
When I instantiate an instance of the object elsewhere in my code, such as
new System::MemoryPool<ParticleShape>(10, 100);
I get the following compile error:
System::AbstractFactory<T>::CreateItem(void) could not deduce template argument for 'T'.
My AbstractFactory class is also a template class, I defined _factory as a private composite object of MemoryPool with type T. I would like it so whenever I instantiated an object of MemoryPool with a type, say MemoryPool of integers, it would initialize the composite _factory with type int.
Is there a way of doing this?
Edit: here is the CreateItem method, in its infancy:
template <typename T>
inline const std::shared_ptr<T> CreateItem()
{
return std::shared_ptr<T>(new T);
}
You've cut out a lot of your code, but at a guess, you have something like this:
template<typename T>
class AbstractFactory {
// ......
template <typename T>
inline const std::shared_ptr<T> CreateItem()
{
return std::shared_ptr<T>(new T);
}
};
The inner template hides the outer value of T - to call this, you'd have to do something like:
AbstractFactory<Anything> factory;
std::shared_ptr<int> pInt = factory.CreateItem<int>();
As you can see, the inner function has a completely independent template parameter from the outer class. You'll probably want to just remove the template parameter from the inner function, so it takes the outer class's template parameter.
I can't say for sure since the AbstractFactory code is missing, but it appears that CreateItem is a template method within AbstractFactory and the compiler can't figure out which version to call.
It's hard to say something definite since you don't show all the code, but it looks like you need to say CreateItem<T>() instead of CreateItem(). A function template that has no (regular) arguments cannot deduce any of its template arguments. They must be specified explicitly.

Using decltype in a late specified return in CRTP base class

I'm trying to use decltype in the late specified return of a member function in a CRTP base class and it's erroring with: invalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >.
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
explicit AnyOp(Functor func) : func_(func) {}
template<class Foo>
bool call_with_foo(const Foo &foo) const
{
//do whatever
}
private:
Functor func_;
};
I'm basically trying to move all of the sfinae boiler plate into a base class so I don't need to repeat it for every Operation that I create (currently each operation has 6 different calls and there are ~50 operations so there is quite a lot of repetition with the enable_if's).
I've tried a solution which relied on overloading but one of the types which may be passed is anything that's callable(this can be a regular functor from C++03 or a C++0x lambda) which I bound to a std::function, unfortunately, the overhead from std::function, although very minimal, actually makes a difference in this application.
Is there a way to fix what I currently have or is there a better solution all together to solve this problem?
Thanks.
You are, as another answer describes already, trying to access a member of a class in one of the class' base class. That's going to fail because the member is yet undeclared at that point.
When it instantiates the base class, it instantiates all its member declarations, so it needs to know the return type. You can make the return type be dependent on Foo, which makes it delay the computation of the return type until Foo is known. This would change the base class like the following
// ignore<T, U> == identity<T>
template<typename T, typename Ignore>
struct ignore { typedef T type; };
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
This artificially makes the static_cast cast to a type dependent on Foo, so it does not immediately require a complete Op type. Rather, the type needs to be complete when operator() is instantiated with the respective template argument.
You are trying to refer to a member of a class from one of its own base classes, which will fail since the class's body doesn't exist within its base class. Can you pass the logic for computing the return type of call_with_foo as a metafunction to the base class? Is that logic ever going to be complicated?
Another option, depending on how much flexibility you have in changing your class hierarchy (and remember that you have template typedefs), is to have the wrapper inherit from the implementation class rather than the other way around. For example, you can write a AddParensWrapper<T> that inherits from T and has operator() that forwards to T::call_with_foo. That will fix the dependency problem.