Content deleted Content added
fixed typo |
No edit summary |
||
(41 intermediate revisions by 34 users not shown) | |||
Line 1:
{{Short description|C++ programming technique}}
'''Substitution failure is not an error''' ('''SFINAE''') refers to a situation in [[C++]] where an invalid substitution of [[template (programming)|template]] parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.<ref>{{cite book | last=Vandevoorde | first=David | coauthors=Nicolai M. Josuttis | title=C++ Templates: The Complete Guide | publisher=Addison-Wesley Professional | year=2002 | isbn=0-201-73484-2}}</ref>▼
▲'''Substitution failure is not an error''' ('''SFINAE''')
Specifically, when creating a candidate set for [[overload resolution]], some (or all) candidates of that set may be the result of
==Example==
The following example illustrates a basic instance of SFINAE:
<
struct Test {
};
template <typename T>
void f(typename T::foo) {} // Definition #1
template <typename T>
void f(T) {}
int main() {
// thanks to SFINAE. return 0;
}
</syntaxhighlight>
Here, attempting to use a non-class type in a qualified name (<code>T::foo</code>) results in a deduction failure for <code>f<int></code> because <code>int</code> has no nested type named <code>foo</code>, but the program is well-formed because a valid function remains in the set of candidate functions.
Although SFINAE was initially introduced to avoid creating ill-formed programs when unrelated template declarations were visible (e.g., through the inclusion of a header file), many developers later 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 example, SFINAE can be used to determine if a type contains a certain typedef:
<
#include <iostream>
template <typename T>
struct
// foobar. };
struct
};
int main() {
return 0;
}
</syntaxhighlight>
When <code>T</code> has the nested type <code>foobar</code> defined, the instantiation of the first <code>test</code> works and
== C++11 simplification ==
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.▼
In [[C++11]], the above code could be simplified to:
<syntaxhighlight lang="cpp">
#include <iostream>
#include <type_traits>
template <typename T, typename = void>
struct HasTypedefFoobar : std::false_type {};
template <typename T>
struct HasTypedefFoobar<T, std::void_t<typename T::foobar>> : std::true_type {};
struct Foo {
using foobar = float;
};
int main() {
std::cout << std::boolalpha;
std::cout << HasTypedefFoobar<int>::value << std::endl;
std::cout << HasTypedefFoobar<Foo>::value << std::endl;
return 0;
}
</syntaxhighlight>
With the standardisation of the detection idiom in the [http://en.cppreference.com/w/cpp/experimental/lib_extensions_2 Library fundamental v2 (n4562)] proposal, the above code could be re-written as follows:
<syntaxhighlight lang="cpp">
#include <iostream>
#include <type_traits>
template <typename T>
using HasTypedefFoobarUnderlying = typename T::foobar;
struct Foo {
using foobar = float;
};
int main() {
std::cout << std::boolalpha;
std::cout << std::is_detected<HasTypedefFoobarUnderlying, int>::value << std::endl;
std::cout << std::is_detected<HasTypedefFoobarUnderlying, Foo>::value << std::endl;
return 0;
}
</syntaxhighlight>
▲
==References==
{{reflist}}
{{C++ programming language}}
▲{{use dmy dates|date=January 2012}}
[[Category:C++]]
[[Category:Articles with example C++ code]]
[[Category:Software design patterns]]
|