Le 31/05/14 23:36, pfultz2 a écrit :
Ok, I can see the advantage of using macros, but please not too much. Yes, of course, that is the only macro that is required, and only because without it can be error prone(perhaps there is another way, but I am unaware of).
I like concept::models. tick_traits doesn't mean nothing significant. Yes, it probably would be better for me to use `models`.
Why do you need tick:ops? This will bring in the query operations(such as `returns`, `has_type`, `has_template`, etc), plus also the placholders(so you can just use `_`,`_1`,`_2`). If the concept is defined in the namespace concepts this is not needed as all these is also in the concepts namespace. Maybe the user should not define its concepts in the same namespace.
I have the impression that the the underlying classes behind the macros are more complex as it seems that they have been adapted so that tht macros can generate the code. No, the classes and macros are really orthogonal. The only complexity added to the classes is that they store the base tratis and refinements so that you can see which of the base traits have failed. Which is completely unrelated to the macros. I believe you "sur parolle". What about needing to use placeholders when stating refinement? Why do you need
TICK_TRAIT(is_x, is_Y<_>) instead of TICK_TRAIT(is_X, is_Y)
I really prefer the last one (even if the 42is magic). I need to admit that the macro TICK_VALID could be useful. Except using just the `concepts::valid_expr` is problematic. If someone forgets to put in the hack(which is easy to do), it can lead to unintended compile errors. That is why the `TICK_VALID` macro is required.
I don't see the risk to be a valid reason to don't make it public and documenting it. Let the user the choice to don't use macros please.
BTW, how do you know how many template parameters has the concept? That comes from how many parameters are used in the requires function.
Yes, but the macro needs to generate the is_trait class. Ah, I see it on
the code now, you have genrated a variadic template for any is_trait.
template
Could a concept in your library have a non-type template parameter? It could, but behind scenes it would require wrapping it in a type. Athough, I could work on adding better support for non-type template parameters.
Isn't this a consequence of using macros?
No need for placeholders in Eric version. Actually, Eric does use placeholders as well, I'm not sure the reason. Yes, I see them also. However, the reason I use placeholder expressions is better operability with current type traits. Eric's versions requires wrapping it in another class. Yes, this allows you to write
|TICK_TRAIT(is_incrementable, std::is_integral<_>)|
Also, another reason placeholders are used is overall simplicity. They are all type traits(ie `std::integral_constant
` actually), and they work with other traits. The classes with the `requires` functions are just implementation details, this is to help avoid confusion about which class is to be used where. So, for example, if I want to refine the `is_incrementable` all I have to do is write `refines >` whereas in Eric's version if I write `refines<Incrementble>` it could lead to a compile error. Where I should have written `refinesconcepts::Incrementable` instead.
This depends where your concept is defined. If it is defined in concepts this works ;-) You have the same namespace problem if the traits are defined in different namespapces.
This FusionSequence concept is not completely necessary even if it could be clearer. We need just
struct SomeConcept { template<class T> auto requires(T&& x) -> decltype(concepts::valid_expr( concepts::is_true(boost::fusion::is_sequence<T>{}) )); }; This doesn't do the same thing. Perhaps its due to my poorly named example.
Agreed.
It should be called `has_fusion_foo`, like this:
TICK_TRAIT(has_fusion_foo) { template<class T> auto requires(T&& x) -> TICK_VALID( returnsboost::fusion::is_sequence<_>(x.foo()) ); }; Please could you explain what
Using Eric's framework:
struct FusionSequence { template<class T> auto requires(T&& x) -> decltype(concepts::valid_expr( concepts::is_true(boost::fusion::is_sequence<T>{}) )); };
struct FusionFoo { template<class T> auto requires(T&& x) -> decltype(concepts::valid_expr( concept::model_of<FusionSequence>(x.foo()) )); }; This check the function member foo returns a model of a Fusion sequence, isn't it? template<class T> using has_fusion_foo = concept::model
; Finally, I don't support adding nested types, like in the example you gave with Why? Its better to write it as a seperate trait, like this:
template
using addable_result = boost::identity () + std::declval<U>())>; This allows for better reusability and composability. All good reasons, but as always is a taste question. Is there something
returns
I prefer the concept::models
expression to the trait expression tick::trait . Maybe I might blend the two together and have `tick::models `.
Why not.
I suggest you to provide a non-macro library that will be at least as expressive as Eric's one and only on top of this expressive library add some macros that make the user life easier. A non-macro version of the library is already provided with the exception of `TICK_VALID`. The only reason a non-macro version of `TICK_VALID` is not provided is because I feel it can be too error-prone.
See above. Best, Vicente