Le 09/03/2016 08:34, paul Fultz a écrit :
On 03/09/2016 08:43 AM, paul Fultz wrote: ...I guess people have different ways of learning a library. I wonder what is needed to be explained better in a initial overview of the library. Please do not take it a a criticism of any kind. That's just an impression I've got. I could be way off the mark.. I often am... I read
On Tuesday, March 8, 2016 4:58 PM, Vladimir Batov
wrote: the docs... twice... well, I tried... :-) I was not able to find an answer to a nagging question -- why I might need the library? What does it do that the standard C++ does not? To me the Quick Start felt more like Quick Start to Confusion. :-) Literally I felt like the deeper into the docs I was going the more alarmed I was. Maybe I need a little more explanation of components in the Quick Start Guide. Perhaps, also, a comparison of writing some of the examples without using the library. The recursive print example is simple, but the technique could apply anytime you needed generic serialization of data. I have written code like that without using this library, so I can see benefit of using it for this particular case. So perhaps, writing a comparison without the library might make that clearer.
Yes, please, show us some examples.
"We can make it (the functor) behave like a regular function" I assume by functor, you mean function, as the library doesn't support functors and is beyond the scope of this library. Some parts of the C++ community name a function object a functor. It ha nothing to be with the applicative, functor, monad in type classes.
In all honesty I don't think I ever had such a need. Usually IMO the conversion is the other way around -- a reg. function into a functor. I think it happens pretty much automatically. Well, the library provides help for that as well, because currently in C++ you can't pass generic functions to other functions, like this:
std::accumulate(v.begin(), v.end(), 0, std::max); // Compile error
However, BOOST_FIT_LIFT will let you do that:
std::accumulate(v.begin(), v.end(), 0, BOOST_FIT_LIFT(std::max)); Maybe it is worth noting that these is a C++17/20 proposal to manage with this case.
[1] p0119r1 - Overload sets as function arguments http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf
"if we construct the class as a global variable"
Should I be excited about it? Globals are often a royal pain. Do I want to construct it a a global variable? | Whats the pain about these Global variables? They are const, can be namespaced, and work just like free functions. However, they do have several advantages.
First, by making them objects we can turn functions into first-class citizens.
Note that we do that now with function objects and lambdas. This is a major argument that belongs to the motivation. You library works with and build high order functions (HOF).
This allows for functions to be easily passed around to other functions. In fact, almost all the functions in this library are declared this way. This make the functions(and adaptors) easily composable. For example, if you wanted to write a function to do for_each over a tuple, you can easily compose the `unpack` adaptor with the `by` adaptor:
BOOST_FIT_STATIC_FUNCTION(for_each_tuple) = compose(unpack, by); As others have noted you should separate the the high order function definition from the possibility to define them globally.
auto for_each_tuple = compose(unpack, by); An alternative to use global function is to define function factories auto for_each_tuple() { return compose(unpack, by); } However this needs an extra level of parenthesis for_each_tuple()([](auto x) { std::cout << x << std::endl; })(t); Maybe it is worth talking of what is behind this style (point-free style or tacit programming) https://en.wikipedia.org/wiki/Tacit_programming
So the `by` adaptor will call a function for each parameter, and the `unpack` adaptor will unpack the elements of the tuple to each parameter. By composing them together we can call a function for each element in a tuple. So, you can write a function to print each value in a tuple, like this:
auto t = std::make_tuple(1, 2); for_each_tuple([](auto x) { std::cout << x << std::endl; })(t);
So by passing functions to other functions, we can easily write some very sophisticated functions without having to resort to metaprogramming. Just as a comparison, here is how you could write for_each_tuple without this library:
namespace detail { template
void for_each(T&& t, F f, seq ) { auto l = { (f(std::get<Is>(t)), 0)... }; } } template
void for_each_tuple(std::tuple const& t, F f) { detail::for_each(t, f, detail::gen_seq ()); } It is more code, with more C++ cleverness going on.
This is s a good example, and of course will need to compare performances at compile time and run-time.
Secondly, by making them objects, it allows us to decorate or enhance functions. C++ doesn't have support for python-like decorators, so if you want to enhance a function, it will need to be a function object through and through.
"BOOST_FIT_STATIC_FUNCTION" | A macro? For C++14? Really? And given you mention it about 20 times just in the Quick Start section it seems quite pivotal for the library... Should I be excited about it? Macros are often a royal pain... Wrapping functors and lambdas in a macro?.. seems like I need quite a bit of
convincing I might want that.
C++17 will be adding support for inline variables, so in the future this macro will be unnecessary. For now, it will take care of statically initializing the function and avoiding possible ODR issues. Any reference to something that will appear in the future standard and describe that your macros are a way to emulate a future feature would be much appreciated. Could you elaborate how inline variables are related?
Furthermore, dealing with inconsistencies and bugs across multiple platforms is a real pain. For example, MSVC has lots of bugs with constexpr that can affect statically initializing the function object. Not everyone needs constexpr. So maybe this use case should be moved to
So this macro provides workarounds so the it can be initialized statically. I don't see the macro as problematic, and without the macro is more problematic. Only if the user needs to declare them globally. However, you can write it without the macro like this:
template<class T> struct static_const_storage { static constexpr T value = T(); };
template<class T> constexpr T static_const_storage<T>::value;
template<class T> constexpr const T& static_const_var(const T&) { return detail::static_const_storage<T>::value; } I believe that there are a lot of users that would prefer to write the code that follows once a library provide the previous one static constexpr auto&& for_each_tuple = static_const_var(compose(unpack, by));
This of course, will only work on a fairly compliant C++11 compilers. It doesn't work on MSVC. Does it works with a MSVC C++14? Also, it won't work when using lambdas. No doubt, C++14 gets rid of a lot of macro usages, but C++14 is still lacking in many areas, so macros are still needed to fill in these gaps. You need to let the user choose. If the user is using a C++14 compliant compiler, would it need the macros? If not it is not worth presenting it as something capital. This belong to the workaround and emulations and I could appreciate having those macros, but having the equivalent C++ code is better.
For a library to be accepted the user has to understand the purpose/value of it and to get excited about it. I did not get it. In fact, I got the opposite... but I a not the brightest "bulb" in the pack...
Thanks for the feedback, I probably should discuss more of the advantages of using function objects in the documentation to make it clear to more people. Yes I've said not all the people knows about High order functional
I agree with that and I suggested Paul from the beginning to move this to an Advanced section. The fact that the library uses it to define the global function is of no concern for the users. Only if a user wants to define a global HOF, then those macros can help them. the advanced usage. AN alternative that you could or not have is to require better compilers. as e.g. Boost.Hana does. programming. You should explain and make reference to external resources as needed. Best, Vicente