$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] RFC: type erasure
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2011-05-24 18:50:57
AMDG
On 05/24/2011 02:07 PM, Vicente Botet wrote:
>
> Steven Watanabe-4 wrote:
>> On 05/23/2011 02:34 PM, Vicente Botet wrote:
>>>
>>> I like how concepts are materialized using a template class that
>>> implements
>>> the default behavior of the concept and that can be specialized to map
>>> type
>>> to concepts. I understand that you need a second step to introduce the
>>> functions themselves specializing concept_interface.
>>>
>>> What I don't understand is the overloading issues. Could you use a
>>> concrete
>>> example to try to clarify the problems you have addressed?
>>>
>>
>> Okay. Problem 1: Name hiding for member functions.
>>
>> typedef mpl::vector<
>> callable<int(int)>,
>> callable<double(double)>
>>> test_concept;
>>
>> If we just use the basic definition of
>> concept_interface, the second overload
>> will hide the first since the inheritance
>> structure looks like:
>>
>> struct callable1 {
>> int operator()(int);
>> };
>>
>> struct callable2 : callable1 {
>> double operator()(double);
>> };
>>
>
> I find this normal and expected behavior, so I don't see yet why do you need
> to avoid this hiding.
>
It's normal in the sense that it's what C++
does by default. I don't see how it can possibly
be the expected behavior that:
struct func {
template<class T>
T operator()(T t) { return t; }
};
typedef mpl::vector<
callable<int(int)>,
callable<double(double)>
> test_concept;
func f1;
any<test_concept> f(f1);
f(1); // calls func::operator()<double>??
From the point of view of someone trying to
use the library, the two instances of callable
are equal. Having one hide the other is surprising.
> I don't understand the use case of the example: when a using declaration
> will be needed?
>
I can't parse this sentence.
>> For free functions, I had a problem akin to name
>> hiding when I defined a single namespace scope
>> overload with concept_interface arguments. Using
>> an inline friend function that takes the derived
>> type works with some care to avoid duplicate
>> definitions.
>>
>
> I'm sorry but I don't reach to see what is the real problem. I guess it is
> because I don't see the need of introducing the using sentence. Please could
> you present a real concrete case of overloading free functions that needs
> two different specializations of concept interface?
>
Consider operator+. Either the first argument
or the second argument or both may be a
type_erasure::any. I need two specializations,
because there are two arguments. To use
friend function defined inline I have to
inject operator+ into exactly one of the
arguments.
I originally tried to handle free functions with
namespace scope overloads like this:
template<class Base, class T, class U, class R>
typename rebind_any<Base, R>::type
operator+(
const concept_interface<addable<T, U, R>, Base, T>&, const U&);
template<class Base, class T, class U, class R>
typename rebind_any<Base, R>::type
operator+(
const T&, const concept_interface<addable<T, U, R>, Base, U>&);
template<class Base1, class Base2, class T, class U, class R>
typename rebind_any<Base, R>::type
operator+(
const concept_interface<addable<T, U, R>, Base1, T>&,
const concept_interface<addable<T, U, R>, Base2, U>&);
Unfortunately, this failed with the example
print_sequence.cpp, because of
ostreamable<_os, const char*>, ostreamable<_os, _t>
Only one of these was being considered
for overload resolution.
>>> You can check the tests for details on what I expect
>>> to work. Most of the tests for specific concepts
>>> have a test_overload test case.
>>>
>>>
> I've read some of them. I guess I understand what you expect to work, but I
> don't see why you need to specialize twice the concept_interface class for
> the same concept.
I couldn't get all the tests to pass with any other
solution I tried. If you have a simpler way to
specialize concept_interface for ostreamable or
callable that passes all my tests I'd love to
hear about it, but I've tried and this is the
best I could come up with.
To summarize the reasons for multiple specializations:
- For member functions, the second and subsequent instances
of a concept need to be treated differently from
the first, because they need an extra using declaration
(which would be ill-formed in the first occurrence).
- For non-member functions, one specialization is needed
for each argument that can be a type_erasure::any to
make sure that the function gets added to the overload
set regardless of what subset of the arguments is erased.
In Christ,
Steven Watanabe