Content deleted Content added
m Changed identifier names for clarity (an identifier called "type" leads to sentences containing many derivates of the word "type", increasing cognitive burden on the reader). |
No edit summary |
||
(46 intermediate revisions by 39 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>▼
{{Use dmy dates|date=December 2023}}
▲'''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 substituting deduced template arguments for the template parameters. If an error occurs during substitution, the compiler removes the potential overload from the candidate set instead of stopping with a compilation error, provided the substitution error is one the C++ standard grants such treatment.<ref>International Organization for Standardization. "ISO/IEC 14882:2003, Programming languages — C++", § 14.8.2.</ref> If one or more candidates remain and overload resolution succeeds, the invocation is well-formed.▼
▲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::
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}}
[[Category:C++]]
[[Category:Articles with example C++ code]]
[[Category:Software design patterns]]
|