51

What is SFINAE in C++?

Can you please explain it in words understandable to a programmer who is not versed in C++? Also, what concept in a language like Python does SFINAE correspond to?

sbi
  • 219,715
  • 46
  • 258
  • 445
Jim
  • 513
  • 5
  • 4
  • @aaa: Yes, I do. Not familiar will all the rules related to them though. – Jim Aug 04 '10 at 16:34
  • Though it lacks the Python orientation, http://stackoverflow.com/questions/982808/c-sfinae-examples is nearly a duplicate. I don't think there really is a direct analog in Python. SFINAE is used primarily for template metaprogramming, which all happens at compile time -- but Python mostly doesn't differentiate strongly between compile time and run time like C++. – Jerry Coffin Aug 04 '10 at 16:34
  • @Jerry: I have seen that thread. Didn't understand a thing. – Jim Aug 04 '10 at 16:35
  • may be this help? http://www.boost.org/doc/libs/1_43_0/libs/utility/enable_if.html – Anycorn Aug 04 '10 at 16:37
  • @aaa: Would you call me dumb if I say "no"? :-| – Jim Aug 04 '10 at 16:45
  • no, I learned C++ after I come from python, and to me it did not make sense until I found a need for it (I had to learn template meta-programming first) – Anycorn Aug 04 '10 at 16:53
  • @Jerry The python bent made this question different for me. I know essentially no C++, but just learned what a template was because it was explained with respect to python. I see python explained in terms of C++ all the time, but rarely C++ explained in terms of python. This was fun. – Wilduck Aug 04 '10 at 18:43
  • I had no idea there was such an acronym as SFINAE – Warren P Aug 04 '10 at 19:47

5 Answers5

123

Warning: this is a really long explanation, but hopefully it really explains not only what SFINAE does, but gives some idea of when and why you might use it.

Okay, to explain this we probably need to back up and explain templates a bit. As we all know, Python uses what's commonly referred to as duck typing -- for example, when you invoke a function, you can pass an object X to that function as long as X provides all the operations used by the function.

In C++, a normal (non-template) function requires that you specify the type of a parameter. If you defined a function like:

int plus1(int x) { return x + 1; }

You can only apply that function to an int. The fact that it uses x in a way that could just as well apply to other types like long or float makes no difference -- it only applies to an int anyway.

To get something closer to Python's duck typing, you can create a template instead:

template <class T>
T plus1(T x) { return x + 1; }

Now our plus1 is a lot more like it would be in Python -- in particular, we can invoke it equally well to an object x of any type for which x + 1 is defined.

Now, consider, for example, that we want to write some objects out to a stream. Unfortunately, some of those objects get written to a stream using stream << object, but others use object.write(stream); instead. We want to be able to handle either one without the user having to specify which. Now, template specialization allows us to write the specialized template, so if it was one type that used the object.write(stream) syntax, we could do something like:

template <class T>
std::ostream &write_object(T object, std::ostream &os) {
    return os << object;
}

template <>
std::ostream &write_object(special_object object, std::ostream &os) { 
    return object.write(os);
}

That's fine for one type, and if we wanted to badly enough we could add more specializations for all the types that don't support stream << object -- but as soon as (for example) the user adds a new type that doesn't support stream << object, things break again.

What we want is a way to use the first specialization for any object that supports stream << object;, but the second for anything else (though we might sometime want to add a third for objects that use x.print(stream); instead).

We can use SFINAE to make that determination. To do that, we typically rely on a couple of other oddball details of C++. One is to use the sizeof operator. sizeof determines the size of a type or an expression, but it does so entirely at compile time by looking at the types involved, without evaluating the expression itself. For example, if I have something like:

int func() { return -1; }

I can use sizeof(func()). In this case, func() returns an int, so sizeof(func()) is equivalent to sizeof(int).

The second interesting item that's frequently used is the fact that the size of an array must to be positive, not zero.

Now, putting those together, we can do something like this:

// stolen, more or less intact from: 
//     http://stackoverflow.com/questions/2127693/sfinae-sizeof-detect-if-expression-compiles
template<class T> T& ref();
template<class T> T  val();

template<class T>
struct has_inserter
{
    template<class U> 
    static char test(char(*)[sizeof(ref<std::ostream>() << val<U>())]);

    template<class U> 
    static long test(...);

    enum { value = 1 == sizeof test<T>(0) };
    typedef boost::integral_constant<bool, value> type;
};

Here we have two overloads of test. The second of these takes a variable argument list (the ...) which means it can match any type -- but it's also the last choice the compiler will make in selecting an overload, so it'll only match if the first one does not. The other overload of test is a bit more interesting: it defines a function that takes one parameter: an array of pointers to functions that return char, where the size of the array is (in essence) sizeof(stream << object). If stream << object isn't a valid expression, the sizeof will yield 0, which means we've created an array of size zero, which isn't allowed. This is where the SFINAE itself comes into the picture. Attempting to substitute the type that doesn't support operator<< for U would fail, because it would produce a zero-sized array. But, that's not an error -- it just means that function is eliminated from the overload set. Therefore, the other function is the only one that can be used in such a case.

That then gets used in the enum expression below -- it looks at the return value from the selected overload of test and checks whether it's equal to 1 (if it is, it means the function returning char was selected, but otherwise, the function returning long was selected).

The result is that has_inserter<type>::value will be l if we could use some_ostream << object; would compile, and 0 if it wouldn't. We can then use that value to control template specialization to pick the right way to write out the value for a particular type.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 13
    *obligatory "wish I could upvote this more than once" comment* Great explanation, I learned something too :) – Thomas Aug 04 '10 at 18:05
  • 2
    This is a thorough explanation, with decent examples too. – Carlos Aug 04 '10 at 20:38
  • 1
    Hmm, last time I checked, this particular thing gave inconsistent results among different compilers. Testing again: GCC - fine, VC++ 2005 (sorry for old version) - everything is printable, codepad.org - "Line 12: error: array bound is not an integer constant", Comeau Online - `static_assert(is_printable::value, "int ok")` fails. I wish **BE student** would read this post, because this is some real material for "testing standard compliance of various compiler wrt templates" :). I have no idea which compiler to trust in this case... – UncleBens Aug 04 '10 at 20:57
  • 5
    "an array of pointers to functions that return `char`" - as written isn't the argument actually a 'pointer to array of `char`'? – Mike Dinsdale Aug 04 '10 at 22:49
  • @Mike: Oops - yes. A pointer to a function would need yet another set of parentheses. Though it doesn't make a huge difference -- the zero-size array is the what matters. – Jerry Coffin Aug 05 '10 at 00:06
  • @UncleBens: You raise a good point. 1) the limits of what are allowed isn't entirely clear, and 2) even in cases where it is clear, not all compilers agree anyway. Using SFINAE portably is a challenge... – Jerry Coffin Aug 05 '10 at 00:31
  • It is possible that the problem is with this particular example. Perhaps if you had chosen a simpler problem for demonstration, compilers could handle it better. The unclarity seems to come from what to thing about `sizeof(ref() << val())`. This is evaluating an expression, not a simple function call (behind that expression there could be either a free function call or a member function call, so the situation is very complicated). – UncleBens Aug 05 '10 at 00:52
  • @Mark Rushakoff: I will if you tell me how... I can't find a button or link anywhere. – Thomas Aug 05 '10 at 07:28
  • @Thomas: [The "Start a bounty" button is available after the question is two days old.](http://blog.stackoverflow.com/2010/06/improvements-to-bounty-system/) – Mark Rushakoff Aug 05 '10 at 10:38
  • Arigato Gozaimasu, @Jerry! :-) – Jim Aug 07 '10 at 19:02
  • 10
    "If `stream << object` isn't a valid expression, the `sizeof` will yield 0" -> This is wrong. `sizeof` can never be applied to invalid expressions, and it most certainly would never return 0, because even empty structs take up 1 byte of memory. "the zero-size array is what matters" -> Also wrong. The reason I used the array in the original code is that I needed a way to map an arbitrary expression to some type. The `sizeof` is just a stepping stone to that goal. It maps an expression to a `size_t`, and the array type constructor maps that `size_t` to a type. Now do I get my Nobel prize? ;-) – fredoverflow Sep 26 '10 at 23:23
  • 10
    Note that in C++0x, mapping expressions to types is trivial thanks to the `decltype` operator. The first `test` overload can thus be simplified to `test(decltype(ref() << val())*);`. Note the complete absence of arrays. All I need is a function that takes a pointer to some valid type. It does not matter if it is a pointer to an output stream (C++0x solution) or a pointer to an array of characters whose size does not matter (C++98 solution). So you see, zero-sized arrays really have nothing to do with it at all. – fredoverflow Sep 26 '10 at 23:43
  • 1
    The parameter to function template `static char test` from your answer: *an array of pointers to functions that return char* shouldn't be : *a pointer to char array* ? – Mr.Anubis Nov 14 '11 at 17:39
  • Won't this fail on a compiler where sizeof(char) == sizeof(short) == sizeof(int) == sizeof(long), which is allowed (since short is only guaranteed to be _at least as big as_ char, and so on for int and long)? So the size of both test functions could be 1. Admittedly, that would be a strange design, but a system where they were all 32 bits isn't impossible to imagine. – David Conrad Jun 01 '12 at 23:36
  • Very good answer, but the analogy to Python duck typing is flawed. Duck typing is fundamentally different from C++'s static typing which templates preserve. I'd say that polymorphism with virtual methods is closer to duck typing conceptually. With templates it's all static, it's compile-time polymorphism. – Eli Bendersky Jun 21 '12 at 03:48
  • @JerryCoffin: [std::nitpicking]. *"sizeof determines the size of a type or an expression,"* .... Should it not be *"sizeof determines the size of a type, or **the type of** an expression"*. It probably hurts readability but it is accurate now. (+1, BTW). – Nawaz Jun 30 '12 at 05:36
  • 1
    @JerryCoffin: I'm pretty much sure this part is completely wrong : *"If stream << object isn't a valid expression, the sizeof will yield 0, which means we've created an array of size zero, which isn't allowed. This is where the SFINAE itself comes into the picture. Attempting to substitute the type that doesn't support operator<< for U would fail, because it would produce a zero-sized array."*... That time **never** comes when `sizeof` returns zero, and the SFINAE doesn't come into picture when it sees zero-sized array. In fact, `sizeof` can **never** return `0`.. [Contd.] – Nawaz Jun 30 '12 at 06:04
  • 1
    [Contd.].... The SFINAE comes into picture much before that. It is when the expression in the `sizeof` turns out to be invalid. – Nawaz Jun 30 '12 at 06:04
  • @JerryCoffin: One more incorrect description : *"The other overload of test is a bit more interesting: it defines a function that takes one parameter: **an array of pointers to functions that return char**"*.. No, the parameter is : a pointer to char array of size `sizeof(expr)`. Note that the parameter is of the form of `char (*v)[N]`, not of the form of `char (*v[N])()` which is actually an array of pointers to function returning `char`. :-) – Nawaz Jun 30 '12 at 08:12
  • Can you explain what the `typedef boost::integral_constant type;` is for here? – szx Jun 03 '13 at 20:57
  • @szx for the selection(tag dispatch) purpose. the `type` either gives `true_type` or `false_type`. – Koushik Shetty Jan 14 '14 at 11:39
12

If you have some overloaded template functions, some of the possible candidates for use may fail to be compilable when template substitution is performed, because the thing being substituted may not have the correct behaviour. This is not considered to be a programming error, the failed templates are simply removed from the set available for that particular parameter.

I have no idea if Python has a similar feature, and don't really see why a non-C++ programmer should care about this feature. But if you want to learn more about templates, the best book on them is C++ Templates: The Complete Guide.

  • 4
    "[I] don't really see why a non-C++ programmer should care about this feature." <-- because I am learning C++ now. – Jim Aug 04 '10 at 16:39
  • 8
    @Jim Well, SFINAE should be well down your list of things you really need to know. –  Aug 04 '10 at 16:43
  • 7
    +1 It is important to note that SFINAE is only available when determining the substitution, that is when the compiler checks the signature. Once the signature is matched and the compiler selects a particular template, any later error IS an error and the compiler will not test other potential template candidates. – David Rodríguez - dribeas Aug 04 '10 at 16:46
  • 3
    It's fine knowing it now, but you're not going to fully grok it until you're much more experienced with the language. I've used C++ for well over a decade and this isn't an aspect I need to be familiar with to be effective. – Kylotan Aug 04 '10 at 16:57
  • @David - yes, that's a very important point and one that can frustrate the ever living hell out of you if you run into it. – Edward Strange Aug 04 '10 at 17:08
9

SFINAE is a principle a C++ compiler uses to filter out some templated function overloads during overload resolution (1)

When the compiler resolves a particular function call, it considers a set of available function and function template declarations to find out which one will be used. Basically, there are two mechanisms to do it. One can be described as syntactic. Given declarations:

template <class T> void f(T);                 //1
template <class T> void f(T*);                //2
template <class T> void f(std::complex<T>);   //3

resolving f((int)1) will remove versions 2 and three, because int is not equal to complex<T> or T* for some T. Similarly, f(std::complex<float>(1)) would remove the second variant and f((int*)&x) would remove the third. The compiler does this by trying to deduce the template parameters from the function arguments. If deduction fails (as in T* against int), the overload is discarded.

The reason we want this is obvious - we may want to do slightly different things for different types (eg. an absolute value of a complex is computed by x*conj(x) and yields a real number, not a complex number, which is different from the computation for floats).

If you have done some declarative programming before, this mechanism is similar to (Haskell):

f Complex x y = ...
f _           = ...

The way C++ takes this further is that the deduction may fail even when the deduced types are OK, but back substitution into the other yield some "nonsensical" result (more on that later). For example:

template <class T> void f(T t, int(*)[sizeof(T)-sizeof(int)] = 0);

when deducing f('c') (we call with a single argument, because the second argument is implicit):

  1. the compiler matches T against char which yields trivially T as char
  2. the compiler substitutes all the Ts in the declaration as chars. This yields void f(char t, int(*)[sizeof(char)-sizeof(int)] = 0).
  3. The type of the second argument is pointer to array int [sizeof(char)-sizeof(int)]. The size of this array may be eg. -3 (depending on your platform).
  4. Arrays of length <= 0 are invalid, so the compiler discards the overload. Substitution Failure Is Not An Error, the compiler won't reject the program.

In the end, if more than one function overload remains, the compiler uses conversion sequences comparison and partial ordering of templates to select one that is the "best".

There are more such "nonsensical" results that work like this, they are enumerated in a list in the standard (C++03). In C++0x, the realm of SFINAE is extended to almost any type error.

I won't write an extensive list of SFINAE errors, but some of the most popular are:

  • selecting a nested type of a type that doesn't have it. eg. typename T::type for T = int or T = A where A is a class without a nested type called type.
  • creating an array type of nonpositive size. For an example, see this litb's answer
  • creating a member pointer to a type that's not a class. eg. int C::* for C = int

This mechanism is not similar to anything in other programming languages I know of. If you were to do a similar thing in Haskell, you'd use guards which are more powerful, but impossible in C++.


1: or partial template specializations when talking about class templates

Community
  • 1
  • 1
jpalecek
  • 47,058
  • 7
  • 102
  • 144
  • `sizeof(char)-sizeof(int)` is an expression of type `size_t`, so it can never be negative; it may be 4294967293U, for example. – musiphil May 19 '12 at 08:27
7

Python won't help you at all. But you do say you're already basically familiar with templates.

The most fundamental SFINAE construct is usage of enable_if. The only tricky part is that class enable_if does not encapsulate SFINAE, it merely exposes it.

template< bool enable >
class enable_if { }; // enable_if contains nothing…

template<>
class enable_if< true > { // … unless argument is true…
public:
    typedef void type; // … in which case there is a dummy definition
};

template< bool b > // if "b" is true,
typename enable_if< b >::type function() {} //the dummy exists: success

template< bool b >
typename enable_if< ! b >::type function() {} // dummy does not exist: failure
    /* But Substitution Failure Is Not An Error!
     So, first definition is used and second, although redundant and
     nonsensical, is quietly ignored. */

int main() {
    function< true >();
}

In SFINAE, there is some structure which sets up an error condition (class enable_if here) and a number of parallel, otherwise conflicting definitions. Some error occurs in all but one definition, which the compiler picks and uses without complaining about the others.

What kinds of errors are acceptable is a major detail which has only recently been standardized, but you don't seem to be asking about that.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • As it is, the code is just in error: "`class "enable_if" has no member "type"`" and "`cannot overload functions distinguished by return type alone`". `function` should be a template, and the (potentially) failing part should depend on template arguments? – UncleBens Aug 04 '10 at 21:31
  • @Uncle: oops, I did oversimplify. SFINAE doesn't work in a non-template environment! – Potatoswatter Aug 04 '10 at 22:03
3

There is nothing in Python that remotely resembles SFINAE. Python has no templates, and certainly no parameter-based function resolution as occurs when resolving template specialisations. Function lookup is done purely by name in Python.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365