Alp Mestanogullari's Blog

Introduction to SFINAE

Posted in Uncategorized by alpmestan on 2009/10/29

Basically, SFINAE (for the smart guys who can remember the whole name : Substitution Failure Is Not An Error) is what makes this code compile.

struct Test 
{
    typedef int type;
};
 
template < typename T > 
void f( typename T::type ) {} // definition #1
 
template < typename T > 
void f( T ) {}                // definition #2
 
f< Test > ( 10 ); // calls #1 
f< int > ( 10 );  //calls #2 without error, thanks to SFINAE

To make it short (but not too much), if you have several overloads for a function, but particularly one of them being template, then if the template one doesn’t match the call you’re currently doing, the compiler — instead of raising a bright, clear and boring error — will try the other ones. In our case, the first definition of f asks for the type parameter to have a nested type type defined (either via class, struct, enum or typedef). Fortunately, Test has one ! But our lonely int type hasn’t. Again, fortunately, the compiler, thanks to SFINAE, will not issue an error and will call #2.

Ok, you got it, but now wonder how can this be useful ? Okay, imagine we basically are working on a widget library. After a huge amount of work, we came up with the following code :

class label
{
};

class button
{
};

Yeah, impressive, isn’t it ?
Okay, now, say we want to write show functions, to be able to show our two widgets. Basically, we can just write two overloads. But it’ll base the overload resolution on the strict name of the type. What if we rather want the overload resolution to be done using the structure of our type ? For example, depending on the presence of a ‘label_tag’ inner typedef, or ‘button_tag’, for button.

Then,, first, we’d modify our two classes this way :

class label
{
public:
    typedef void label_tag;
};

class button
{
public:
    typedef void button_tag;
};

Then, how can we apply the SFINAE principle here ? Well, here is one way :

template <typename widget_type>
typename widget_type::label_tag show(widget_type& w)
{
    std::cout<< "I'm a label" << std::endl;
}

template <typename widget_type>
typename widget_type::button_tag show(widget_type& w)
{
    std::cout << "I'm a button" << std::endl;
}

And then, the main function and its output :

int main()
{
    label l; 
    button b;
    show(l);
    show(b);
    return 0;
}
/* Output :
 * I'm a label
 * I'm a button
 */

Got it ? ;)

Maybe I’ll dive into more advanced uses of SFINAE (more complex and powerful interface detection) in further posts.

Stay tuned !

About these ads
Tagged with: , ,

4 Responses

Subscribe to comments with RSS.

  1. bjarne said, on 2009/10/29 at 5:35 pm

    wordpress is eating &lt and &gt, code should look like this

    template &lttypename widget_type&gt
    typename widget_type::label_tag show(widget_type& w)
    {
    std::cout<< "I'm a label" << std::endl;
    }

    template &lttypename widget_type&gt
    typename widget_type::button_tag show(widget_type& w)
    {
    std::cout << "I'm a button" << std::endl;
    }

  2. bjarne said, on 2009/10/29 at 5:39 pm

    sorry! should be < and >

  3. rmn said, on 2009/10/29 at 6:18 pm

    You might find this interesting:
    http://cplusplus.co.il/2009/09/11/substitution-failure-is-not-an-error-1/

  4. alpmestan said, on 2009/10/29 at 8:52 pm

    Right, should be okay now, thanks.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 251 other followers

%d bloggers like this: