
on Sat Oct 13 2012, Andrzej Krzemienski <akrzemi1-AT-gmail.com> wrote:
2012/10/12 Dave Abrahams <dave@boostpro.com>
on Fri Oct 12 2012, Andrew Sutton <asutton.list-AT-gmail.com> wrote:
If I remember correctly, we assumed that a conversion requirement on the result of an operation, would actually convert (if necessary).
What does "if necessary" mean? I can think of at least two different ways to decide whether a conversion is necessary.
If the expression returns bool, no conversion is necessary. If it does not, then a conversion is needed.
Sorry, that's still too vague to tell me what you mean. Surely this has nothing to do with "bool-ness," so I have to assume bool shows up in an example you have in mind. Could you show a concrete example with specific requirements?
Pardon me, if I completely misunderstood your concern.
BTW, Doug Gregor is the one who explained all this to me, years ago, so it's his concern first.
This is how I understand the issue you describe:
We have a concept requirement like this:
concept Operation<typename Op, typename T> = requires(Op op, T t) { //... bool = { op(t) }; // "convertible to bool" }
I have to admit that I'm not entirely familiar with the new-fangled syntax being proposed, but I think I can muddle through your use of it here. Operation<Op,T> says that declval<Op>()(declval<T>()) is valid and convertible to bool, right?
We have the following function template
template< typename Op, typename T > requires Operation<Op, T> bool fun(Op op, T t) { return true && op(t); }
We have a following concrete type that models Operation:
class FunnyBool{...}; // almost like bool class X{...}; // which will become T FunnyBool operation(X x) {...}; // which will become Op bool operator&& (bool a, FunnyBool b) {}; // which will do some unexpected thing
Yes, you're on the right track here...
When we instantiate:
fun(operation, X{});
which operator&& will be picked? (bool, bool) or (bool, FunnyBool)?
This is the question you ask.
Well, I'm not sure that my entire concern can be captured in this one example, but this question is certainly an instance of my concern.
Am I right? If so, the answer I find the most logical would be is since the concept is only aware that the type is convertible to bool and can only rely on this information, when function fun() is instantiated with operation and X, it only sees a restricted version of operation and X and indirectly FunnyBool as though 'through concept Operation' and must convert FunnyBool to bool before applying operator &&.
That's what the pseudo-signature approach does, so you and I agree on that much. In fact, these are the "loose match" semantics you were objecting to earlier. :-) Notationally speaking, I think pseudo-signatures are *much* more suggestive of those semantics than are valid expressions. The bigger problem is that the valid expression approach also makes it possible/easy to specify requirements where the type corresponding to bool in this example is never explicitly named, e.g.: bool = { true && op(t) }; value_type = { *it++ }; etc. IIUC these sorts of things cause big problems for typechecking (exponential explosions?) and usability, but I'd have to defer to others to describe in detail what those issues are.
Of course this is achievable only in concepts as language feature. Any use-pattern-based concept library will not be able to implement this behavior, as far as I am aware.
On the other hand, a pseudo-signature-based library conceivably could. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost