From: Andy Venikov on
Johannes Schaub (litb) wrote:
<snip>
>>
>
> No. instantiation of "enable_if<false, type>" doesn't fail. It's the access
> to "::type", which happens during deduction at the very toplevel, which
> fails.

Still not clear.

The way I understand it now, is that if the error happens while trying
to instantiate a class during template argument deduction, then SFINAE
kicks in. As in if the statement that generates an error is not in the
body of the class but in <...> of the template specialization, then it's
OK.

I re-organized my original example with this in mind. And I got some
surprising results.
It compiles on both gcc 4.4 and on Comeau online. But I get different
result. Gcc is able to tell the difference and has_foo<...>::value is
true only for the types that have function foo. Comeau always returns
false. Now I wander what compiler is right?

Here's the re-worked example:
(the idea was to move sizeof(&T::foo) from within class body to class
declaration>


-----> Code start
typedef unsigned int size_t;

template <bool Test, typename T = void>
struct enable_if;

template <typename T>
struct enable_if<true, T>
{
typedef T type;
static const bool value = true;
};

template <typename T, typename Enable = void>
struct has_foo
{
static const bool value = false;
};

template <typename T, typename Enable = void>
struct take_address_of_foo
{
static const bool value = false;
};

template <typename T>
struct take_address_of_foo<T,
typename enable_if<0 < sizeof(decltype(&T::foo))>::type>
{
static const bool value = true;
};

template <typename T>
struct has_foo<T, typename enable_if<take_address_of_foo<T>::value>::type>
{
static const bool value = true;
};


struct WithFoo
{
int foo(int, int, int);
};

struct NoFoo
{
};


template <typename T, bool HasFoo = T::value>
struct CompileError
{
typedef typename T::non_existing_type_brrr type;
};

//All lines compile fine. But Comeau alway returns false.
//Gcc returns true for the "WithFoo" case
const bool B1 = has_foo<WithFoo>::value;
const bool B2 = has_foo<NoFoo>::value;
const bool B3 = has_foo<int>::value;

<-------- Code end


Thanks,
Andy.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andy Venikov on
Andy Venikov wrote:
<snip>

Sorry to re-post my question, but I think the question got lost in
between the lines.

The following code compiles fine on both gcc 4.3 and Comeau online (with
and without C++0x support) but produces different results. Gcc returns
what I'd expect (true if T has foo and false if it doesn't) Comeau
always returns false.

I wonder, who's right?

typedef unsigned int size_t;

template <bool Test, typename T = void>
struct enable_if;

template <typename T>
struct enable_if<true, T>
{
typedef T type;
static const bool value = true;
};

template <typename T, typename Enable = void>
struct has_foo
{
static const bool value = false;
};

template <typename T, typename Enable = void>
struct take_address_of_foo
{
static const bool value = false;
};

template <typename T>
struct take_address_of_foo<T,
typename enable_if<0 < sizeof(&T::foo)>::type>
{
static const bool value = true;
};

template <typename T>
struct has_foo<T, typename enable_if<take_address_of_foo<T>::value>::type>
{
static const bool value = true;
};


struct WithFoo
{
int foo(int, int, int);
};

struct NoFoo
{
};


template <typename T, bool HasFoo = T::value>
struct CompileError
{
typedef typename T::non_existing_type_brrr type;
};

//Force compile-error to show the results of has_foo<...>::type
//Comeau alway returns false.
//Gcc returns true for the "WithFoo" case
typedef CompileError<WithFoo, has_foo<WithFoo>::value>::type T1;
typedef CompileError<NoFoo, has_foo<NoFoo>::value>::type T2;
typedef CompileError<int, has_foo<int>::value>::type T3;




> Thanks,
> Andy.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Mathias Gaunard on
On 12 mai, 09:07, Andy Venikov <swojchelo...(a)gmail.com> wrote:
>
> For example, try implementing has_foo<> by taking an address of foo. If foo exists, everything fine. If foo doesn't exist, then you'll get compile-time error no matter what.

It is well-known how to do this, consult the relevant articles.
In C++0x, you can do even better though, you can test any expression,
which allows to take into account conversions and object constness
automatically.


>
> Code:
>
> template <bool Test, typename T = void>
> struct enable_if;
>
> template <typename T>
> struct enable_if<true, T>
> {
> typedef T type;
> static const bool value = true;
>
> };
>
> template <typename T, typename Enable = void>
> struct has_foo
> {
> static const bool value = false;
>
> };
>
> template <typename T>
> struct take_address_of_foo
> {
> static const size_t nTest = sizeof(&T::foo);
> static const bool value = enable_if<nTest>::value;
>
> };
>
> template <typename T>
> struct has_foo<T, typename enable_if<take_address_of_foo<T>::value>::type>
> {
> static const bool value = true;
>
> };

You're doing it wrong, this doesn't test for T::foo in an SFINAE
context.

Here is an example of how to do it.

template<typename T>
struct has_foo
{
private:
struct found {};
struct not_found { char two[2]; };

template<typename X, int (X::*)(int, int, int)>
struct member {};

template<typename X>
static found test(member<X, &X::foo>*);

template<typename X>
static not_found test(...);

public:
static const bool value = sizeof(test<T>(0)) == sizeof(found);
typedef boost::mpl::bool_<value> type;
};


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Ilya Sokolov on
Mathias Gaunard wrote:
> On 12 mai, 09:07, Andy Venikov <swojchelo...(a)gmail.com> wrote:
>> For example, try implementing has_foo<> by taking an address of foo.
>> If foo exists, everything fine. If foo doesn't exist, then you'll
>> get compile-time error no matter what.
>
> It is well-known how to do this, consult the relevant articles.
> In C++0x, you can do even better though, you can test any expression,
> which allows to take into account conversions and object constness
> automatically.

"Solving the SFINAE problem for expressions"
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html

> [snip]
>
> template<typename T>
> struct has_foo
> {
> private:
> struct found {};
> struct not_found { char two[2]; };
>
> template<typename X, int (X::*)(int, int, int)>
> struct member {};
>
> template<typename X>
> static found test(member<X, &X::foo>*);
>
> template<typename X>
> static not_found test(...);
>
> public:
> static const bool value = sizeof(test<T>(0)) == sizeof(found);
> typedef boost::mpl::bool_<value> type;
> };

Is it required by the standard that sizeof(found) != sizeof(not_found)?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Ilya Sokolov on
Andy Venikov wrote:
> Andy Venikov wrote:
> <snip>
>
> Sorry to re-post my question, but I think the question got lost in
> between the lines.
>
> The following code compiles fine on both gcc 4.3 and Comeau online (with
> and without C++0x support) but produces different results. Gcc returns
> what I'd expect (true if T has foo and false if it doesn't) Comeau
> always returns false.
>
> I wonder, who's right?

I don't see anything in the standard that prevents Comeau from matching
partial specialization of task_address_of_foo.

> [snip]

Shorter variant would be:

template <bool Test, typename T = void>
struct enable_if;

template <typename T>
struct enable_if<true, T>
{
typedef T type;
static const bool value = true;
};

template <typename T, typename Enable = void>
struct has_foo
{
static const bool value = false;
};

template <typename T>
struct has_foo<T, typename enable_if<sizeof(&T::foo)>::type>
{
static const bool value = true;
};

or:

template<int>
struct void_
{
typedef void type;
};

template <typename T, typename Enable = void>
struct has_foo
{
static const bool value = false;
};

template <typename T>
struct has_foo<T, typename void_<sizeof(&T::foo)>::type>
{
static const bool value = true;
};

or using cpp0x:

template <typename T, typename Enable = void>
struct has_foo
{
static const bool value = false;
};

template <typename T>
struct has_foo<T, decltype(T::foo)>
{
static const bool value = true;
};

Sadly, for all variants has_foo<WithFoo>::value == false
in como.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]