|
Boost : |
Subject: Re: [boost] enable_if and non-template member functions?
From: Mostafa (mostafa_working_away_at_[hidden])
Date: 2011-08-12 19:42:25
On Fri, 12 Aug 2011 14:14:24 -0700, Jeremiah Willcock
<jewillco_at_[hidden]> wrote:
> On Fri, 12 Aug 2011, Mostafa wrote:
>
>> On Fri, 12 Aug 2011 02:31:10 -0700, John Maddock
>> <boost.regex_at_[hidden]> wrote:
>>
>>>> From your description, I think I've done exactly this. E.g.
>>> --8<---------------cut here---------------start------------->8---
>>> template <class U>
>>> struct X
>>> {
>>> // member function void f(int) becomes something like:
>>> template <class T>
>>> typename enable_if<
>>> mpl::and_<
>>> is_convertible<T,int>
>>> , some_condition_on<U>
>>> >
>>> >::type
>>> f(T x_)
>>> { int x = x_; ... }
>>> };
>>> --8<---------------cut here---------------end--------------->8---
>>> That works as long as the function has at least one parameter that
>>> can be turned into a template, but I have some cases that are
>>> operators or else have no parameters.
>>
>> In case of no-parameter functions or operators, what's wrong with:
>>
>> template <class U>
>> struct T
>> {
>> void f()
>> {
>> f_impl(<static_cast<void *>(0));
>> }
>>
>> private:
>> template <class T>
>> typename enable_if<
>> mpl::and_<
>> is_convertible<T, void *>,
>> some_condition_on<U>
>> >::type
>> f_impl(T)
>> { .... }
>> };
>
> In that case, f would not be covered by SFINAE, since it is not a
> template. Calls to f would fail because of the lack of f_impl,
Yes, I'm proposing moving the SFINAE failure one level deep to point where
f_impl is called.
> but that would be done after overload resolution.
I'm presuming you're talking about choosing between different multiple
return types for no-parameter non-template member functions. For example,
i) if template-parameter U is a class, we would want: CLASS * operator*();
ii) else: void * operator*();
In such a scenario wouldn't one just use a template-selector struct on the
return type? The following example illustrates both scenarios, and it
works on 4.0.1,
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/type_traits.hpp>
#include <iostream>
using namespace boost;
struct CLASS {};
template <class U>
struct T
{
void f()
{
this->f_impl(static_cast<void *>(0));
}
void bar()
{
std::cout << "Non-class template parameter instantiations work." <<
std::endl;
}
struct deref
{
template <class R, class ENABLER = void> struct ret;
template <class R>
struct ret<R, typename enable_if<is_class<R> >::type >
{ typedef U * type; };
template <class R>
struct ret<R, typename enable_if<mpl::not_<is_class<R> > >::type >
{ typedef void * type; };
};
typename deref::template ret<U>::type operator*()
{
return this->deref_impl(static_cast<void *>(0));
}
private:
template <class T>
typename enable_if<
mpl::and_<
is_same<T, void *>,
is_class<U>
>
>::type
f_impl(T)
{
std::cout << "Class template parameter instantiations work." <<
std::endl;
}
template <class T>
typename enable_if<
mpl::and_<
is_same<T, void *>,
is_class<U>
>,
/*U **/typename deref::template ret<U>::type
>::type
deref_impl(T)
{
std::cout << "U * ret type." << std::endl;
return 0;
}
template <class T>
typename enable_if<
mpl::and_<
is_same<T, void *>,
mpl::not_<is_class<U> >
>,
/*void **/typename deref::template ret<U>::type
>::type
deref_impl(T)
{
std::cout << "void * ret type." << std::endl;
return 0;
}
};
int main()
{
T<CLASS> ins;
ins.f();
*ins;
T<int> ins2;
ins2.bar();
*ins2;
// ins2.f(); //Expected compiler error.
return 0;
}
- Mostafa
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk