mirror of
https://github.com/boostorg/utility.git
synced 2025-08-03 14:54:31 +02:00
for review
[SVN r1506]
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
<META name="GENERATOR" content="hevea 1.06">
|
<META name="GENERATOR" content="hevea 1.06">
|
||||||
</HEAD>
|
</HEAD>
|
||||||
<BODY >
|
<BODY >
|
||||||
<!--HEVEA command line is: hevea -nosymb -noiso -pedantic -v enable_if_docs_for_boost.tex -->
|
<!--HEVEA command line is: hevea enable_if_docs_for_boost.tex -->
|
||||||
<!--HTMLHEAD-->
|
<!--HTMLHEAD-->
|
||||||
<!--ENDHTML-->
|
<!--ENDHTML-->
|
||||||
<!--PREFIX <ARG ></ARG>-->
|
<!--PREFIX <ARG ></ARG>-->
|
||||||
@@ -20,18 +20,19 @@
|
|||||||
<img border="0" src="c++boost.gif" align="center" width="277" height="86">enable_if</h1>
|
<img border="0" src="c++boost.gif" align="center" width="277" height="86">enable_if</h1>
|
||||||
<BR>
|
<BR>
|
||||||
<BR>
|
<BR>
|
||||||
Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.<BR>
|
Copyright 2003 Jaakko J<EFBFBD>rvi, Jeremiah Willcock, Andrew Lumsdaine.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<!--TOC section Introduction-->
|
<!--TOC section Introduction-->
|
||||||
|
|
||||||
<H2><A NAME="htoc1">1</A> Introduction</H2><!--SEC END -->
|
<H2><A NAME="htoc1">1</A> Introduction</H2><!--SEC END -->
|
||||||
|
|
||||||
<A NAME="introduction"></A>
|
<A NAME="introduction"></A>
|
||||||
The <TT>enable_if</TT> template is a tool for selectively including
|
The <TT>enable_if</TT> family of templates is a set of tools to allow a function template or a class template specialization
|
||||||
functions into the overload resolution set based on the properties of
|
to include or exclude itself from a set of matching functions or specializations
|
||||||
the template arguments. For example, one can define function templates that
|
based on properties of its template arguments.
|
||||||
|
For example, one can define function templates that
|
||||||
are only enabled for, and thus only match, an arbitrary set of types
|
are only enabled for, and thus only match, an arbitrary set of types
|
||||||
defined by a traits class. The <TT>enable_if</TT> template can also be
|
defined by a traits class. The <TT>enable_if</TT> templates can also be
|
||||||
applied to enable class template specializations. Applications of
|
applied to enable class template specializations. Applications of
|
||||||
<TT>enable_if</TT> are discussed in length
|
<TT>enable_if</TT> are discussed in length
|
||||||
in [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>] and [<A HREF="#jarvi:03:c++typeclasses"><CITE>2</CITE></A>].<BR>
|
in [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>] and [<A HREF="#jarvi:03:c++typeclasses"><CITE>2</CITE></A>].<BR>
|
||||||
@@ -43,10 +44,15 @@ in [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>] and&n
|
|||||||
<A NAME="sec:synopsis"></A>
|
<A NAME="sec:synopsis"></A>
|
||||||
<PRE>
|
<PRE>
|
||||||
namespace boost {
|
namespace boost {
|
||||||
template <bool B, class T = void> struct enable_if;
|
template <class Cond, class T = void> struct enable_if;
|
||||||
template <bool B, class T = void> struct disable_if;
|
template <class Cond, class T = void> struct disable_if;
|
||||||
template <bool B, class T> struct enable_if_lazy;
|
template <class Cond, class T> struct lazy_enable_if;
|
||||||
template <bool B, class T> struct disable_if_lazy;
|
template <class Cond, class T> struct lazy_disable_if;
|
||||||
|
|
||||||
|
template <bool B, class T = void> struct enable_if_c;
|
||||||
|
template <bool B, class T = void> struct disable_if_c;
|
||||||
|
template <bool B, class T> struct lazy_enable_if_c;
|
||||||
|
template <bool B, class T> struct lazy_disable_if_c;
|
||||||
}
|
}
|
||||||
</PRE>
|
</PRE>
|
||||||
<!--TOC subsection Background-->
|
<!--TOC subsection Background-->
|
||||||
@@ -85,50 +91,80 @@ where the return type is invalid. If this was an error, adding an unrelated func
|
|||||||
Due to the SFINAE principle the above example is not, however, erroneous.
|
Due to the SFINAE principle the above example is not, however, erroneous.
|
||||||
The latter definition of <TT>negate</TT> is simply removed from the overload resolution set.<BR>
|
The latter definition of <TT>negate</TT> is simply removed from the overload resolution set.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
The <TT>enable_if</TT> template is a tool for controlled creation of the SFINAE
|
The <TT>enable_if</TT> templates are tools for controlled creation of the SFINAE
|
||||||
conditions.<BR>
|
conditions.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<!--TOC section The <TT>enable_if</TT> template-->
|
<!--TOC section The <TT>enable_if</TT> templates-->
|
||||||
|
|
||||||
<H2><A NAME="htoc4">2</A> The <TT>enable_if</TT> template</H2><!--SEC END -->
|
<H2><A NAME="htoc4">2</A> The <TT>enable_if</TT> templates</H2><!--SEC END -->
|
||||||
|
|
||||||
<A NAME="enable_if"></A>
|
<A NAME="enable_if"></A>
|
||||||
The definition of <TT>enable_if</TT> is as follows:
|
The names of the <TT>enable_if</TT> templates have three parts: an optional <TT>lazy_</TT> tag,
|
||||||
|
either <TT>enable_if</TT> or <TT>disable_if</TT>, and an optional <TT>_c</TT> tag.
|
||||||
|
All eight combinations of these parts are supported.
|
||||||
|
The meaning of the <TT>lazy_</TT> tag is described in Section <A HREF="#sec:enable_if_lazy">3.3</A>.
|
||||||
|
The second part of the name indicates whether a true condition argument should
|
||||||
|
enable or disable the current overload.
|
||||||
|
The third part of the name indicates whether the condition argument is a <TT>bool</TT> value
|
||||||
|
(<TT>_c</TT> suffix), or a type containing a static <TT>bool</TT> constant named <TT>value</TT> (no suffix).
|
||||||
|
The latter version interoperates with Boost.MPL. <BR>
|
||||||
|
<BR>
|
||||||
|
The definitions of <TT>enable_if_c</TT> and <TT>enable_if</TT> are as follows (we use <TT>enable_if</TT> templates
|
||||||
|
unqualified but they are in the <TT>boost</TT> namespace).
|
||||||
<PRE>
|
<PRE>
|
||||||
|
|
||||||
template <bool B, class T = void>
|
template <bool B, class T = void>
|
||||||
struct enable_if {
|
struct enable_if_c {
|
||||||
typedef T type;
|
typedef T type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct enable_if<false, T> {};
|
struct enable_if_c<false, T> {};
|
||||||
|
|
||||||
|
template <class Cond, class T = void>
|
||||||
|
struct enable_if : public enable_if_c<Cond::value, T> {};
|
||||||
|
|
||||||
</PRE>
|
</PRE>
|
||||||
An instantiation of the <TT>enable_if</TT> template with the parameter
|
An instantiation of the <TT>enable_if_c</TT> template with the parameter
|
||||||
<TT>B</TT> as <TT>true</TT> contains a member type <TT>type</TT>, defined
|
<TT>B</TT> as <TT>true</TT> contains a member type <TT>type</TT>, defined
|
||||||
to be <TT>T</TT>. If <TT>B</TT> is
|
to be <TT>T</TT>. If <TT>B</TT> is
|
||||||
false, no such member is defined. Thus
|
<TT>false</TT>, no such member is defined. Thus
|
||||||
<TT>enable_if<B, T>::type</TT> is either a valid or an invalid type
|
<TT>enable_if_c<B, T>::type</TT> is either a valid or an invalid type
|
||||||
expression, depending on the value of <TT>B</TT>.
|
expression, depending on the value of <TT>B</TT>.
|
||||||
When valid, <TT>enable_if<B, T>::type</TT> equals <TT>T</TT>.
|
When valid, <TT>enable_if_c<B, T>::type</TT> equals <TT>T</TT>.
|
||||||
The <TT>enable_if</TT> can thus be used for controlling when functions are considered for
|
The <TT>enable_if_c</TT> template can thus be used for controlling when functions are considered for
|
||||||
overload resolution and when not.
|
overload resolution and when they are not.
|
||||||
For example, the following function is defined for all arithmetic types (according to the
|
For example, the following function is defined for all arithmetic types (according to the
|
||||||
classification of the <A HREF="http://www.boost.org/libs/type_traits">Boost type_traits library</A>):
|
classification of the <A HREF="http://www.boost.org/libs/type_traits">Boost type_traits library</A>):
|
||||||
<PRE>
|
<PRE>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t) { return t; }
|
typename enable_if_c<boost::is_arithmetic<T>::value, T>::type
|
||||||
|
foo(T t) { return t; }
|
||||||
|
|
||||||
</PRE>
|
</PRE>
|
||||||
The <TT>disable_if</TT> template is provided as well, and has the
|
The <TT>disable_if_c</TT> template is provided as well, and has the
|
||||||
same functionality as <TT>enable_if</TT> except for the negated condition. The following
|
same functionality as <TT>enable_if_c</TT> except for the negated condition. The following
|
||||||
function is enabled for all non-arithmetic types.
|
function is enabled for all non-arithmetic types.
|
||||||
<PRE>
|
<PRE>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename disable_if<boost::is_arithmetic<T>::value, T>::type foo(T t) { return t; }
|
typename disable_if_c<boost::is_arithmetic<T>::value, T>::type
|
||||||
|
bar(T t) { return t; }
|
||||||
|
|
||||||
|
</PRE>
|
||||||
|
For easier syntax in some cases and interoperation with Boost.MPL we provide versions of
|
||||||
|
the <TT>enable_if</TT> templates taking any type with a <TT>bool</TT> member constant named
|
||||||
|
<TT>value</TT> as the condition argument.
|
||||||
|
The MPL <TT>bool_</TT>, <TT>and_</TT>, <TT>or_</TT>, and <TT>not_</TT> templates are likely to be
|
||||||
|
useful for creating such types. Also, the traits classes in the Boost.Type_traits library
|
||||||
|
follow this convention.
|
||||||
|
For example, the above example function <TT>foo</TT> can be alternatively written as:
|
||||||
|
<PRE>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t) { return t; }
|
||||||
|
|
||||||
</PRE>
|
</PRE>
|
||||||
<!--TOC section Using <TT>enable_if</TT>-->
|
<!--TOC section Using <TT>enable_if</TT>-->
|
||||||
@@ -140,17 +176,17 @@ The <TT>enable_if</TT> templates are defined in
|
|||||||
<TT>boost/utility/enable_if.hpp</TT>, which is included by <TT>boost/utility.hpp</TT>.<BR>
|
<TT>boost/utility/enable_if.hpp</TT>, which is included by <TT>boost/utility.hpp</TT>.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
The <TT>enable_if</TT> template can be used either as the return type, or as an
|
The <TT>enable_if</TT> template can be used either as the return type, or as an
|
||||||
extra argument. For example, the <TT>foo</TT> function below could also be written
|
extra argument. For example, the <TT>foo</TT> function in the previous section could also be written
|
||||||
as:
|
as:
|
||||||
<PRE>
|
<PRE>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);
|
T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);
|
||||||
|
|
||||||
</PRE>Hence, an extra argument of type <TT>void*</TT> is added, but it is given
|
</PRE>Hence, an extra parameter of type <TT>void*</TT> is added, but it is given
|
||||||
a default value to keep the argument hidden from the client code.
|
a default value to keep the parameter hidden from client code.
|
||||||
Note that the type parameter was not given to <TT>enable_if</TT>, the default
|
Note that the second template argument was not given to <TT>enable_if</TT>, as the default
|
||||||
<TT>void</TT> gives the desired type.<BR>
|
<TT>void</TT> gives the desired behavior.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
Whether to write the enabler as an argument or within the return type is
|
Whether to write the enabler as an argument or within the return type is
|
||||||
largely a matter of taste, but for certain functions, only one
|
largely a matter of taste, but for certain functions, only one
|
||||||
@@ -176,17 +212,17 @@ template <class T, class Enable = void>
|
|||||||
class A { ... };
|
class A { ... };
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class A<T, typename enable_if<is_integral<T>::value>::type> { ... };
|
class A<T, typename enable_if<is_integral<T> >::type> { ... };
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class A<T, typename enable_if<is_float<T>::value>::type> { ... };
|
class A<T, typename enable_if<is_float<T> >::type> { ... };
|
||||||
|
|
||||||
</PRE>Instantiating <TT>A</TT> with any integral type matches the first specialization,
|
</PRE>Instantiating <TT>A</TT> with any integral type matches the first specialization,
|
||||||
whereas any floating point type matches the second one. All other types
|
whereas any floating point type matches the second one. All other types
|
||||||
match the primary template.
|
match the primary template.
|
||||||
The condition can be any compile-time boolean expression that depends on the
|
The condition can be any compile-time boolean expression that depends on the
|
||||||
template arguments of the class.
|
template arguments of the class.
|
||||||
Note that no type parameter is given to <TT>enable_if</TT>; the default (<TT>void</TT>)
|
Note that again, the second argument to <TT>enable_if</TT> is not needed; the default (<TT>void</TT>)
|
||||||
is the correct value.<BR>
|
is the correct value.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<!--TOC subsection Overlapping enabler conditions-->
|
<!--TOC subsection Overlapping enabler conditions-->
|
||||||
@@ -203,10 +239,12 @@ lead to ambiguities. For example:
|
|||||||
<PRE>
|
<PRE>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<boost::is_integral<T>::value, void>::type foo(T t) {}
|
typename enable_if<boost::is_integral<T>, void>::type
|
||||||
|
foo(T t) {}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<boost::is_arithmetic<T>::value, void>::type foo(T t) {}
|
typename enable_if<boost::is_arithmetic<T>, void>::type
|
||||||
|
foo(T t) {}
|
||||||
|
|
||||||
</PRE>
|
</PRE>
|
||||||
All integral types are also arithmetic. Therefore, say, for the call <TT>foo(1)</TT>,
|
All integral types are also arithmetic. Therefore, say, for the call <TT>foo(1)</TT>,
|
||||||
@@ -230,7 +268,7 @@ and there is variation among compilers. For example:
|
|||||||
template <class T, class U> class mult_traits;
|
template <class T, class U> class mult_traits;
|
||||||
|
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
typename enable_if<is_multipliable<T, U>::value, typename mult_traits<T, U>::type>::type
|
typename enable_if<is_multipliable<T, U>, typename mult_traits<T, U>::type>::type
|
||||||
operator*(const T& t, const U& u) { ... }
|
operator*(const T& t, const U& u) { ... }
|
||||||
|
|
||||||
</PRE>Assume the class template <TT>mult_traits</TT> is a traits class defining
|
</PRE>Assume the class template <TT>mult_traits</TT> is a traits class defining
|
||||||
@@ -243,16 +281,16 @@ Now, trying to invoke (some other overload) of <TT>operator*</TT> with, say, ope
|
|||||||
for which <TT>is_multipliable<C, D>::value</TT> is <TT>false</TT>
|
for which <TT>is_multipliable<C, D>::value</TT> is <TT>false</TT>
|
||||||
and <TT>mult_traits<C, D>::type</TT> is not defined is an error on some compilers.
|
and <TT>mult_traits<C, D>::type</TT> is not defined is an error on some compilers.
|
||||||
The SFINAE principle is not applied because
|
The SFINAE principle is not applied because
|
||||||
the invalid type occurs as an argument to another template. The <TT>enable_if_lazy</TT>
|
the invalid type occurs as an argument to another template. The <TT>lazy_enable_if</TT>
|
||||||
and <TT>disable_if_lazy</TT> templates can be used in such
|
and <TT>lazy_disable_if</TT> templates (and their <TT>_c</TT> versions) can be used in such
|
||||||
situations:
|
situations:
|
||||||
<PRE>
|
<PRE>
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
typename enable_if_lazy<is_multipliable<T, U>::value, mult_traits<T, U> >::type
|
typename lazy_enable_if<is_multipliable<T, U>, mult_traits<T, U> >::type
|
||||||
operator*(const T& t, const U& u) { ... }
|
operator*(const T& t, const U& u) { ... }
|
||||||
|
|
||||||
</PRE>The second argument of <TT>enable_if_lazy</TT> must be a class type
|
</PRE>The second argument of <TT>lazy_enable_if</TT> must be a class type
|
||||||
that defines a nested type named <TT>type</TT> whenever the first
|
that defines a nested type named <TT>type</TT> whenever the first
|
||||||
parameter (the condition) is true.<BR>
|
parameter (the condition) is true.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
@@ -269,10 +307,12 @@ some compilers (e.g. GCC 3.2) diagnose the following two functions as ambiguous:
|
|||||||
template <class T> struct dummy { dummy(int) {} };
|
template <class T> struct dummy { dummy(int) {} };
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t);
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t);
|
typename disable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
|
|
||||||
</PRE>Two workarounds can be applied:
|
</PRE>Two workarounds can be applied:
|
||||||
<UL><LI>
|
<UL><LI>
|
||||||
@@ -283,10 +323,12 @@ it to hide the parameter from the caller. For example:
|
|||||||
template <class T> struct dummy { dummy(int) {} };
|
template <class T> struct dummy { dummy(int) {} };
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t, dummy<0> = 0);
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t, dummy<0> = 0);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t, dummy<1> = 0);
|
typename disable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t, dummy<1> = 0);
|
||||||
</PRE><BR>
|
</PRE><BR>
|
||||||
<BR>
|
<BR>
|
||||||
<LI>Define the functions in different namespaces and bring them into a common
|
<LI>Define the functions in different namespaces and bring them into a common
|
||||||
@@ -295,21 +337,24 @@ namespace with <TT>using</TT> declarations:
|
|||||||
|
|
||||||
namespace A {
|
namespace A {
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t);
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace B {
|
namespace B {
|
||||||
template <class T>
|
template <class T>
|
||||||
typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t);
|
typename disable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
}
|
}
|
||||||
|
|
||||||
using A::foo;
|
using A::foo;
|
||||||
using B::foo;
|
using B::foo;
|
||||||
|
|
||||||
</PRE>
|
</PRE>
|
||||||
Note that the second workaround above cannot be used for member
|
Note that the second workaround above cannot be used for member
|
||||||
templates. On the other hand, operators do not accept extra arguments,
|
templates. On the other hand, operators do not accept extra arguments,
|
||||||
which makes the first workaround unusable. As the net effect,
|
which makes the first workaround unusable. As the net effect,
|
||||||
neither of the workarounds are of help for templated operators that
|
neither of the workarounds are of assistance for templated operators that
|
||||||
need to be defined as member functions (assignment and
|
need to be defined as member functions (assignment and
|
||||||
subscript operators).
|
subscript operators).
|
||||||
</UL>
|
</UL>
|
||||||
@@ -317,19 +362,19 @@ subscript operators).
|
|||||||
|
|
||||||
<H2><A NAME="htoc10">4</A> Acknowledgements</H2><!--SEC END -->
|
<H2><A NAME="htoc10">4</A> Acknowledgements</H2><!--SEC END -->
|
||||||
|
|
||||||
We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides and Richard
|
We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides, and Richard
|
||||||
Smith whose findings have influenced the library.<BR>
|
Smith whose findings have influenced the library.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<!--TOC section References-->
|
<!--TOC section References-->
|
||||||
|
|
||||||
<H2>References</H2><!--SEC END -->
|
<H2>References</H2><!--SEC END -->
|
||||||
<DL COMPACT=compact><DT><A NAME="jarvi:03:cuj_arbitrary_overloading"><FONT COLOR=purple>[1]</FONT></A><DD>
|
<DL COMPACT=compact><DT><A NAME="jarvi:03:cuj_arbitrary_overloading"><FONT COLOR=purple>[1]</FONT></A><DD>
|
||||||
Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine.
|
Jaakko J<EFBFBD>rvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine.
|
||||||
Function overloading based on arbitrary properties of types.
|
Function overloading based on arbitrary properties of types.
|
||||||
<EM>C/C++ Users Journal</EM>, 21(6):25--32, June 2003.<BR>
|
<EM>C/C++ Users Journal</EM>, 21(6):25--32, June 2003.<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<DT><A NAME="jarvi:03:c++typeclasses"><FONT COLOR=purple>[2]</FONT></A><DD>
|
<DT><A NAME="jarvi:03:c++typeclasses"><FONT COLOR=purple>[2]</FONT></A><DD>
|
||||||
Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine.
|
Jaakko J<EFBFBD>rvi, Jeremiah Willcock, and Andrew Lumsdaine.
|
||||||
Concept-controlled polymorphism.
|
Concept-controlled polymorphism.
|
||||||
In <EM>Proceedings of Generative Programming and Component
|
In <EM>Proceedings of Generative Programming and Component
|
||||||
Engineering (GPCE'03)</EM>, September 2003.
|
Engineering (GPCE'03)</EM>, September 2003.
|
||||||
@@ -347,7 +392,7 @@ Addison-Wesley, 2002.</DL>
|
|||||||
<hr></hr>
|
<hr></hr>
|
||||||
|
|
||||||
<B>Contributed by:</B> <BR>
|
<B>Contributed by:</B> <BR>
|
||||||
Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine<BR>
|
Jaakko J<EFBFBD>rvi, Jeremiah Willcock and Andrew Lumsdaine<BR>
|
||||||
<EM>{jajarvi|jewillco|lums}@osl.iu.edu</EM><BR>
|
<EM>{jajarvi|jewillco|lums}@osl.iu.edu</EM><BR>
|
||||||
Indiana University<BR>
|
Indiana University<BR>
|
||||||
Open Systems Lab
|
Open Systems Lab
|
||||||
|
Reference in New Issue
Block a user