 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Glen Low Guest
|
Posted: Mon Oct 18, 2004 4:56 pm Post subject: Reusable test for presence of a nested typedef? |
|
|
Warning, SFINAE territory ahead...
One typical formulation of a test for a nested typedef result_type
would be, based on Dewhurstian mechanics:
enum yes_no { yes = 1, no = 2 };
template <typename T> char (*may_have_result_type (typename
T::result_type*)) [yes];
template <typename T> char (*may_have_result_type (...)) [no];
template <typename T> stuct has_result_type
{
enum { value = sizeof (*may_have_result_type <T> (NULL)) = yes };
};
So to test if a type U has a result_type, we simply do has_result_type
<U>::value.
But being a guy who loves reuse, especially when he sees his own code
littered with almost similar instances of the above, I wonder whether
there's a general way of doing this (without bashing clients with a
macro) i.e.
has_typedef <U, result_type>::value OR has_typedef <typename
U::result_type>::value ?
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Terje Slettebų Guest
|
Posted: Mon Oct 18, 2004 8:31 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
"Glen Low" <glenlow (AT) pixelglow (DOT) com> wrote
| Quote: | Warning, SFINAE territory ahead...
|
And if you fail to understand it, don't treat it as an error. ;)
| Quote: | One typical formulation of a test for a nested typedef result_type
would be, based on Dewhurstian mechanics:
enum yes_no { yes = 1, no = 2 };
template <typename T> char (*may_have_result_type (typename
T::result_type*)) [yes];
template <typename T> char (*may_have_result_type (...)) [no];
template <typename T> stuct has_result_type
{
enum { value = sizeof (*may_have_result_type <T> (NULL)) = yes };
};
So to test if a type U has a result_type, we simply do has_result_type
U>::value.
But being a guy who loves reuse, especially when he sees his own code
littered with almost similar instances of the above, I wonder whether
there's a general way of doing this (without bashing clients with a
macro) i.e.
has_typedef <U, result_type>::value OR has_typedef <typename
U::result_type>::value ?
|
I don't think it can be done without a macro. Many good people have tried.
In the Concept Traits library
([url]http://www.neoscientists.org/boost_library_proposals.html)[/url], where Tobias
Schwinger now is co-author, I used macros for detection where you need a
name, as there are headers (in the type_traits_ext directory of the zip-file
there. Sorry, the docs are only in the archive at the moment) for detection
of:
- Non-static members (variables and functions)
- Static members (variables and functions)
- Nested classes or typedefs
- Nested class templates
Regards,
Terje
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
John M. Dlugosz Guest
|
Posted: Tue Oct 19, 2004 4:22 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) wrote in message news:<9215d7ac.0410171513.42ac2620 (AT) posting (DOT) google.com>...
| Quote: | But being a guy who loves reuse, especially when he sees his own code
littered with almost similar instances of the above, I wonder whether
there's a general way of doing this (without bashing clients with a
macro) i.e.
|
What happens when you put those templates as template members of a
class which it itself a template on the type name in question? You
imply that it didn't work?
--John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Glen Low Guest
|
Posted: Tue Oct 19, 2004 5:59 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
| Quote: | But being a guy who loves reuse, especially when he sees his own code
littered with almost similar instances of the above, I wonder whether
there's a general way of doing this (without bashing clients with a
macro) i.e.
has_typedef <U, result_type>::value OR has_typedef <typename
U::result_type>::value ?
I don't think it can be done without a macro. Many good people have tried.
In the Concept Traits library
([url]http://www.neoscientists.org/boost_library_proposals.html)[/url], where Tobias
Schwinger now is co-author, I used macros for detection where you need a
name, as there are headers (in the type_traits_ext directory of the zip-file
there.
|
I thought so.
In the end it wasn't too bad. I was using the presence or absence of a
typedef within an enable_if on an partial specialization, it turns out
all I needed was:
template <typename T> struct exists { enum { value = true }; };
Simple, no? Why does it work... well in the partial specialization I
do:
template <typename T, typename Enable = void> class thing;
template <typename T> class thing <T,
typename enable_if ::type>
{
...
};
So in classic SFINAE style, this will be silently dropped from the
overload set when typename T::result_type doesn't exist. The exists +
enable_if combination only serves to form the type "void" when
result_type does exist.
Of course the exists template is of no use in a non-substitutionary
context, and it might yet blow up in my face on a non-gcc compiler,
but I'm fairly sure it will work on a Standard compliant one.
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Larry Evans Guest
|
Posted: Wed Oct 20, 2004 4:26 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
On 10/18/2004 03:31 PM, Terje Slettebų wrote:
[snip]
| Quote: | I don't think it can be done without a macro. Many good people have tried.
In the Concept Traits library
([url]http://www.neoscientists.org/boost_library_proposals.html)[/url], where Tobias
Schwinger now is co-author, I used macros for detection where you need a
name, as there are headers (in the type_traits_ext directory of the zip-file
there. Sorry, the docs are only in the archive at the moment) for detection
of:
- Non-static members (variables and functions)
- Static members (variables and functions)
- Nested classes or typedefs
- Nested class templates
One example of using boost/mpl/aux_/has_xxx.hpp is: |
<------------------
//Purpose:
// Test use of SFINAE to detect T::nesting_type for any type, T.
#include
namespace boosts
{
BOOST_MPL_HAS_XXX_TRAIT_DEF(nesting_type)
}
struct bool_false{ char c[1];};
struct bool_true { char c[2];};
template<typename T>
struct has_nesting_type
{
template<class C> static bool_true has_nest_type(C::nesting_type*);
template<typename C> static bool_false has_nest_type(...);
enum{ result = sizeof(has_nest_type<T>(0)) == sizeof(bool_true)};
};
struct not_nester{};
struct yes_nester
{
typedef not_nester nesting_type;
};
#include <iostream>
using namespace boost::mpl::aux;
int main(void)
{
std::cout<<"yes_nester="<
std::cout<<"not_nester="<
std::cout<<"===>boostn";
std::cout<<"yes_nester="<
std::cout<<"not_nester="<
return 0;
}
| Quote: | ------------------
The output of this was: |
<------------------
/opt/intel_cc_80/bin/icc -c -MMD -g
-I/home/evansl/prog_dev/boost-root.ln/boost_dev
-I/home/evansl/prog_dev/boost-root.ln -o has_nesting_type.o
has_nesting_type.cpp
/opt/intel_cc_80/bin/icc -g -o has_nesting_type.exe has_nesting_type.o
running has_nesting_type
../has_nesting_type.exe
yes_nester=1
not_nester=0
===>boost
yes_nester=1
not_nester=0
Compilation finished at Sat Mar 6 16:45:52
| Quote: | ------------------
|
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Terje Slettebų Guest
|
Posted: Wed Oct 20, 2004 6:34 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
"Glen Low" <glenlow (AT) pixelglow (DOT) com> wrote
| Quote: | But being a guy who loves reuse, especially when he sees his own code
littered with almost similar instances of the above, I wonder whether
there's a general way of doing this (without bashing clients with a
macro) i.e.
has_typedef <U, result_type>::value OR has_typedef <typename
U::result_type>::value ?
I don't think it can be done without a macro. Many good people have
tried.
In the Concept Traits library
([url]http://www.neoscientists.org/boost_library_proposals.html)[/url], where
Tobias
Schwinger now is co-author, I used macros for detection where you need a
name, as there are headers (in the type_traits_ext directory of the
zip-file
there.
I thought so.
In the end it wasn't too bad. I was using the presence or absence of a
typedef within an enable_if on an partial specialization, it turns out
all I needed was:
template <typename T> struct exists { enum { value = true }; };
Simple, no? Why does it work... well in the partial specialization I
do:
template <typename T, typename Enable = void> class thing;
template <typename T> class thing <T,
typename enable_if ::type
{
...
};
So in classic SFINAE style, this will be silently dropped from the
overload set when typename T::result_type doesn't exist. The exists +
enable_if combination only serves to form the type "void" when
result_type does exist.
|
Clever...
This does actually work. Come to think of it, I've played with this
technique, as well - I even used the same name: "exists" (!) and found it
marvellous simple. As you say, it doesn't work as a general trait (outside
templates) - which was the original request - but it does work in this
context, of eliminating overloads/specialisations during overload
resolution/specialisation selection.
It does actually generalise to detection of member class template, too:
template <typename T, typename Enable = void>
class thing;
template <typename T>
class thing<
T,
typename boost::enable_if<
exists
};
class A
{
public:
template<class T>
struct nested {};
};
class B {};
int main()
{
thing<A> a; // Ok
thing<B> b; // Error
}
Moreover, unlike the pointer-to-member type technique, this one actually
works for reference type members, too (you can't form a pointer to a
reference).
And - I just realised - it also works for private members (!), as the type
or class template is never actually used (and hence checked for access),
only checked for existence.
Thanks for reminding me of this technique. :)
| Quote: | Of course the exists template is of no use in a non-substitutionary
context, and it might yet blow up in my face on a non-gcc compiler,
but I'm fairly sure it will work on a Standard compliant one.
|
It works on Intel C++ 7.1, too (EDG).
Regards,
Terje
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Glen Low Guest
|
Posted: Wed Oct 20, 2004 9:42 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
| Quote: | What happens when you put those templates as template members of a
class which it itself a template on the type name in question? You
imply that it didn't work?
|
Don't understand, please elaborate with an example.
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Glen Low Guest
|
Posted: Thu Oct 21, 2004 7:40 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
| Quote: | One example of using boost/mpl/aux_/has_xxx.hpp is:
------------------
//Purpose:
// Test use of SFINAE to detect T::nesting_type for any type, T.
|
I wanted the converse, i.e. to detect T: for any nested type x.
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Glen Low Guest
|
Posted: Thu Oct 21, 2004 7:41 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
| Quote: | This does actually work. Come to think of it, I've played with this
technique, as well - I even used the same name: "exists" (!) and found it
marvellous simple. As you say, it doesn't work as a general trait (outside
templates) - which was the original request - but it does work in this
context, of eliminating overloads/specialisations during overload
resolution/specialisation selection.
Thanks for reminding me of this technique.
|
No worries.
Unfortunately it can be somewhat deceptive e.g.
template <typename T> struct X <T,
enable_if
<T>::value>::type>
{
}
never actually works for an integral type, since the exists
<T::inner>::value causes the substitution failure anyway. Although for
the case of &&, it does work correctly and as you'd expect.
I find it a little more straightforward and reusable than SFINAE on
overload functions; I've changed my macstl code to use it.
| Quote: | It works on Intel C++ 7.1, too (EDG).
|
Works on MS Visual C++ .NET 2003 too.
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Terje Slettebų Guest
|
Posted: Fri Oct 22, 2004 5:16 pm Post subject: Re: Reusable test for presence of a nested typedef? |
|
|
"Larry Evans" <cppljevans (AT) cox-internet (DOT) com> wrote
| Quote: | On 10/18/2004 03:31 PM, Terje Slettebų wrote:
[snip]
I don't think it can be done without a macro. Many good people have
tried.
In the Concept Traits library
([url]http://www.neoscientists.org/boost_library_proposals.html)[/url], where
Tobias
Schwinger now is co-author, I used macros for detection where you need
a
name, as there are headers (in the type_traits_ext directory of the
zip-file
there. Sorry, the docs are only in the archive at the moment) for
detection
of:
- Non-static members (variables and functions)
- Static members (variables and functions)
- Nested classes or typedefs
- Nested class templates
One example of using boost/mpl/aux_/has_xxx.hpp is:
|
<snip>
Yeah, but, uhm, here you're showing one version using an MPL macro to do it
(BOOST_MPL_HAS_XXX_TRAIT_DEF(nesting_type)), and then one way to do it by
making the trait class "manually":
| Quote: | template<typename T
struct has_nesting_type
{
template
has_nest_type(C::nesting_type*);
template<typename C> static bool_false has_nest_type(...);
enum{ result = sizeof(has_nest_type<T>(0)) == sizeof(bool_true)};
};
|
So... what was the point? OP mentioned both ways, but inquired about the
possibility of doing it without macros, and without having to define a
template like the above.
Regards,
Terje
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|