Erase Type and Variation Function of a Member Template

The example below is a minimal, maybe not very good example of a well-known idiom.
It compiles, and it is so ugly as to be able to keep it minimal, because this is not about the idiom itself.

struct Foo { virtual void fn() = 0; }; template<class T> struct Bar: public Foo { void fn() override { T{}.fn(); } }; struct S { void fn() { } }; int main() { Foo *foo = new Bar<S>{}; foo->fn(); } 

What I’m afraid since an hour ago, how to change it (or even if there is an alternative idiom), introduce the method of variation template.
Obviously, I cannot change the fn function of the Foo class because the virtual and virtual qualifiers do not match the patterns. The same is true for the fn Bar specification, since it must somehow override the one in the base class.

Note.

I strongly suspect that this question may be one of the biggest XYProblem that I have ever seen, I would also like to give a brief description of the real problem.

I have a class that provides two template member methods:

  • the first accepts the template class T , which is not used immediately; instead, it must be stored somehow for later use.

  • the second accepts the variational number of arguments (this is actually a variational function-template member function), and these arguments should be perfectly redirected to the newly created instance of T

Well, the problem is much more complicated, but it is a good approximation to it and should give you an idea of ​​what the goal is.

Edit

I suppose this is somehow similar to higher order functions.
I mean, to solve the problem is really a template function that binds the first argument, but as far as I know, it is impossible, like any other approach that I have studied so far.
Any viable solution expressing the same concept?

+7
c ++ c ++ 11 templates type-erasure variadic-templates
source share
2 answers

In the comments, I mentioned the following approach:

 template<typename T> class Factory { public: template<typename ...Args> auto construct(Args && ...args) { return T(std::forward<Args>(args)...); } }; 

So your first public class method will be something like this:

 template<typename T> auto getFactory() { return Factory<T>(); } 

So:

 auto factory=object.getFactory<someClass>(); // Then later: factory.construct(std::string("Foo"), bar()); // And so on... 

Instead of construct() you can use operator() too, so the second part of this will be simple:

 factory(std::string("Foo"), bar()); // And so on... 

As I said, this is not erasing styles. You cannot use type erasure here.

Having given this a few thoughts, the reason why type erasure cannot be used here is because this instance of type erasure needs to be “self-preserving” or atomic, and you need to do to break atomic erase into two parts or two classes in your case.

This will not work. An erase type, by definition, takes a type and erases it. As soon as your first type of function erases the class method template parameter, what you end up with is an opaque, type-erased object. What is erased is no longer available to the outside world. But you still haven't typed the erasable parameters of your constructor, which happens elsewhere.

You can type-erase the template class and constructor parameters together. You cannot type the template type and constructor parameters separately and then somehow erase the result again.

A simple factory-based approach, like the one I outlined, will be closest to results similar to type erasing if both halves of your desired erase styles appear in the same area, so you can actually avoid erasing styles and instead rely on styles bloated compiler.

+6
source share

I also agree that you cannot do exactly what you want here. I will post what, in my opinion, is the closest option (at least the closest option, different from Samvarshavchik's answer).
I do not expect this answer to solve your problem exactly, but hopefully this will give you some ideas.

  struct Delay // I have no idea what to call this { template <class T> void SetT() { function_ = [](boost::any params){return T(params);} } template <class ... Args> boost::any GetT(Args ... args) { return function_(std::make_tuple(args...)); } private: std::function<boost::any(boost::any)> function_; }; 

The obvious limitation is that anyone who calls GetT must somehow know that T already existed, although you can request a boost::any object for type_info your class if that helps. Another limitation here is that you have to go into T , which takes a boost::any object and knows what to do with it. If you cannot execute T , then you can modify SetT (or create a new member function) as follows:

  template <class F> SetTFactory(F f) { function_ = f; } 

and then use it like:

  Delay d; d.SetTFactory([](boost::any s){return std::string(boost::any_cast<const char*>(s));}); auto s = d.GetT("Message"); assert(s.type() == typeid(std::string)); 

This, of course, represents a number of difficulties that have to be dealt with, so I don’t know how viable this solution will be for you. I think that, in spite of everything else, you will have to rethink your design a little.

+4
source share

All Articles