|
Boost : |
From: Daniel Wallin (dalwan01_at_[hidden])
Date: 2004-11-21 20:50:01
Gennadiy Rozental wrote:
>>>What overloads are you trying to resolve here:
>>>
>>>template<class A0>
>>>void foo(
>>> const A0& a0
>>> , foo_keywords::restrict<A0>::type x = foo_keywords()
>>>)
>>>{
>>> foo_impl(x(a0));
>>>}
>>>
>>>template<class A0, class A1>
>>>void foo(
>>> const A0& a0, const A1& a1
>>> , foo_keywords::restrict<A0,A1>::type x = foo_keywords()
>>>)
>>>{
>>> foo_impl(x(a0, a1));
>>>}
>>
>>There are no more overloads here. But foo is only enabled when the
>>"name" parameter is convertible to char const*:
>
>
> Wait, this is an exact copy of an example you have in "controlling overload
> resolution" section. Any why two functions then?
I'm sorry, I don't know what that means.
> So can you gove me an example of "controlling overload resolution" feature?
I just did. foo is enabled only when 'name' is convertible to char
const*.
>>>As for type restriction I am using typed keywords.
>>
>>But that's not enough! It's too naive. What if you want a function
>>overload:
>>
>> template<class Value>
>> void f(Value);
>>
>> Where Value is restricted to types that are Movable, detectable with
>> is_movable<>.
>>
>>How would you do this?
>
>
> First of all this is comparatevly rarely needed. Accordingly I do not see a
> reasons to supply library solution for this problem.
So we shouldn't care about this use case? Why? To reduce the number of
lines of code in the implementation?
> Whould I ever need
> something like this, I would do:
>
> template<typename Value>
> enable_if<Value is movable,void>
> foo_impl( Value const&, std::string name, Mymode mode )
> {
> }
>
> template<typename Params>
> void foo(Params const& p)
> {
> foo_impl( p[value], p[name], p[mode] );
> }
>
> value above is typelees keyword in my terminology. And no need to mix
> everything into one bowl.
But again, you don't generally have the ability to have a universal
foo() overload that handles the dispatching. You want one for every
overload.
>>Actually, we can't do that with the overload restrictions. I guess we
>>could support it, and maybe we should..
>>
>>Anyway, the code you posted is valid with our library as well, if that
>>you suppress the compilation error by supplying a default value for i2:
>
>
> [solution skipped]
>
> This is not exactly the same thing, and clear source of confusion.
Really? What's the difference?
>>This solution is obviously flawed though, since in general you can't be
>>assumed to be able to change foo() to account for every possible
>>overload.
>
>
> Ok. So what is your solution to the problem of supplying single named
> parameter based interface for dynamically sized series of functions with
> different actual number of arguments?
I would add something to the library to control overload resolution for
this case with SFINAE.
>>>> int v = params[a | 8];
>>>>
>>>>With our library.
>>>
>>>
>>>And now compare: what is more obvious and easier to grasp?
>>
>>Your version is easier to grasp until you have learned the DSL.
>
>
>
>>But the
>>cost of it is that your code won't work in a lot of cases. For instance,
>>the default value expression always has to be compiled.
>
>
> Why is that? Why Couldn't I do the same as what you are doing?
>
> int v = params.has(a) ? params[a] : get_a_default_value();
>
> It's even easier since I do not need to wrap it into bind call.
No, because get_a_default_value() has to compile. Our defaults can be
lazily evaluated, and only compiled when needed.
>>Really? Is the parameter defaults also an implementation detail? As a
>>user, how am I suppose to use your functions if I don't know about these
>>things?
>
>
> Yes. I inclined to think about function parameter default values more in
> terms of implementation details rather than part of interface. You as a
> function user shouldn't based your decisions on the default value for the
> parameter: you have value for this parameter - you supply it. You don't -
> function deals with it itself. This is especially true since in many , many
> cases you just couldn't put default value into function declaration:
>
> int foo( int a, int b = a ) {...}
>
> What we do instead is somehow mimic similar behavior:
>
> int foo( int a, int b = -1 ) {
> if( b = -1 )
> b = a;
> }
>
> So what default value -1 gives you as a function caller?
The value of 'a'?
What you were arguing here however is that it shouldn't even be part of
the interface whether 'b' has a default value or is a required
parameter.
>>>How are you supposed to now from 'select' function interface that
>
> timeout
>
>>>parameter is required iff mode parameter is WAIT? Accordingly in a point
>
> of
>
>>>select function invocation:
>>>
>>>select(( mode =WAIT,priority=2,prefer_output=true));
>>>
>>>You have no way to know that timeout is missing, while in following call
>>>
>>>select(( mode =POOL,priority=0));
>>>
>>>is not.
>>
>>Why? It's a simple precondition that might even be enforced at compile
>>time with our library if you want to.
>
>
> How? I would like to see it. I would like to see you to produce compile time
> error based on runtime value of the variable.
Of course I can't produce compile time errors based on runtime values,
but who said anything about mode being a runtime value? The modes could
just as well be tag types here, in which case it's trivial.
template<class P>
int select_impl(wait_t, P const& args) ..
template<class P>
int select_impl(block_t, P const& args) ..
template<class P>
int select_impl(pool_t, P const& args) ..
template<class P>
int select(P const& args)
{
return select_impl(args[mode], args);
}
-- Daniel Wallin
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk