On Tuesday, December 29, 2015 at 3:56:07 AM UTC-6, Vicente J. Botet Escriba wrote:
Le 27/12/2015 02:54, Paul Fultz II a écrit :
On Friday, December 18, 2015 at 11:20:54 AM UTC-5, Nat Goodspeed wrote:
Our code has any number of instances of this pattern:
template
class SomeTemplate { SomeTemplate(const T& t, const U& u); ... }; template
SomeTemplate make_SomeTemplate(const T& t, const U& u) { return SomeTemplate (t, u); } Am I overlooking a generic boost::make<something>() of this general
form?
This can easily be built using the `fit::construct` function from the Fit library. There are some some specificities my make<> function has: * The template parameter can be a template class, a type constructor or a class
`fit::construct_meta` can be used with a metafunction or a metafunction class.
* The function is customizable
There is no need for customization. Rather `fit::construct` is used to build these functions.
Can fit::construct<> be used like make<>?
Not exactly, rather it is a different approach to polymorphic constructors. The `make<>` function tries to unify everything, and `fit::construct<>` removes boilerplate for writing polymorphic constructors.
Plus, `by` can be used to apply prohejection to handle the different type of deductions necessary. Here's how to build `make` that decays each parameter:
FIT_STATIC_FUNCTION(make_tuple) = fit::constructstd::tuple().by(fit::decay);
We can use `fit::decay` which will decay and unwrap references. For `tie`, we can do our own projection `lvalue`, which really does nothing except ensures that lvalues are passed to the function:
struct lvalue { template<class T> constexpr T& operator()(T& x) const { return x; } }; FIT_STATIC_FUNCTION(tie) = fit::constructstd::tuple().by(lvalue());
The `forward_as_tuple` can also be written always deducing a reference:
struct reference { template<class T> constexpr T&& operator()(T&& x) const { return std::forward<T>(x); } }; FIT_STATIC_FUNCTION(forward_as_tuple) = fit::constructstd::tuple().by(reference()); I don't know what the other think of having several ways to deduce the parameters.
Well its necessary in certain contexts, but it highly depends on the class. Some classes may not have been written to support references or rvalue references.
Of course, this can be used to create a generic factory. The problem with a generic factory is some classes might want different ways of deducing the parameters(perhaps the class doesn't allow for references at all). There could be some metaprogramming done to notify the generic factory, however, it might be easier just to write a custom factory(its only one line of code). So it might be better for the generic factory to have a customization point instead.
Also, the three different factories provided by tuple seem to be a bad choice for the more general construction. It would be better to have three factory type functions like this:
make - deduces lvalues as lvalues and rvalues as rvalues(ie it contains no rvalue references) make_forward - Everything is deduced as reference(like `forward_as_tuple`) make_decay - decay the parameters and unwrap references(like `make_tuple` and `make_pair`)
Of course, this changes what people generally view `make` as. Perhaps a different name could be used other than `make`.
I people needs to make the difference I would prefer to have
make: decay the parameters and unwrap references(like `make_tuple` and `make_pair`) forward_as: Everything is deduced as reference(like `forward_as_tuple`) ....
But you are missing the most important deduction which is deducing lvalues as lvalues and rvalues as rvalues. It currently is missing from standard C++, but it is very useful, and strikes the balance between mostly efficient and mostly safe. `make` is safe but not efficient, and `forward_as` is efficient but not always safe(rvalue references can easily lead to dangling references).
Vicente
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost