
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?
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.
Yes. I would expect that either approach is capable of doing the same.
In fact, these are the "loose match" semantics you were objecting to earlier. :-)
I was not objecting to "loose match". I was trying to say that pseudo-signatures look like normal signatures and might imply that no "loose match" occurs. In contrast, usage patterns look like expressions, and you do expect implicit conversions. Although, I do not find it a major argument against pseudo-signatures.
Notationally speaking, I think pseudo-signatures are *much* more suggestive of those semantics than are valid expressions.
Could you show an example where this is the case? I may be missing something obvious, but I would say it is the other way around.
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.
And since this discussion started because Lorenzo wonders which of the two approaches to take for his library, perhaps this limitation gives us the answer. Regards, &rzej