Content deleted Content added
m →Example |
|||
Line 9:
struct Test
{
typedef int
};
template < typename T >
void f(typename T::
template < typename T >
void f(T) {} // definition #2
{
f<Test>(10); // call #1
Line 27:
Here, attempting to use a non-class type in a qualified name (<code>T::Type</code>) results in a deduction failure for <code>f<int></code> because <code>int</code> has no nested type named <code>Type</code>, but the program is well-formed because a valid function remains in the set of candidate functions.
Although SFINAE was introduced to avoid creating ill-formed programs when unrelated template declarations were visible (e.g., through the inclusion of a header file), many developers found the behavior useful for compile-time introspection. Specifically, it allows a template to determine certain properties of its template arguments at instantiation time.
For <source lang="cpp">
#include <iostream>
template <typename T>
struct has_typedef_type
{
// yes and no are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(typename C::type*);
template <typename>
static no& test(...);
// if the sizeof the result of calling test<T>(0) is equal to the sizeof(yes),
// the first overload worked and T has a nested type named type.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
struct foo
{
typedef float type;
};
int main()
{
std::cout << std::boolalpha;
std::cout << has_typedef_type<int>::value << std::endl;
std::cout << has_typedef_type<foo>::value << std::endl;
}
</source>
When <code>T</code> has the nested type <code>type</code> defined, the instantiation of the first <code>test</code> works and 0 is successfully passed as the null pointer constant. (And the resulting type of the expression is <code>yes</code>.) If it does not work, the only available function is the second <code>test</code>, and the resulting type of the expression is <code>no</code>. (Ellipses are used not only because it will accept any argument, but also because it's conversion rank is lowest, so a call to the first function will be preferred if it is possible; this removes ambiguity.)
Developers of [[Boost C++ Libraries|Boost]] used SFINAE to great effect in boost::enable_if<ref name="enable_if">[http://www.boost.org/doc/libs/release/libs/utility/enable_if.html Boost Enable If]</ref> and in other ways.
==References==
|