<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds/rss-style.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yyj</title>
        <link>https://yyj.us/</link>
        <description>Yingjie Ye's blog. Technical notes and the occasional essay.</description>
        <lastBuildDate>Thu, 10 Sep 2026 06:56:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Astro-Theme-Retypeset with Feed for Node.js</generator>
        <language>en</language>
        <copyright>Copyright © 2026 Yingjie Ye</copyright>
        <atom:link href="https://yyj.us/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[SFINAE: Overloading Member Functions at Compile Time]]></title>
            <link>https://yyj.us/posts/sfinae-compile-time-member-function-overload/</link>
            <guid isPermaLink="false">https://yyj.us/posts/sfinae-compile-time-member-function-overload/</guid>
            <pubDate>Fri, 10 Jan 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[I ran into a problem recently while writing a template class: how does a member function get a default behavior for one specific template<ty...]]></description>
            <content:encoded><![CDATA[<p>I ran into a problem recently while writing a template class: how does a member function get a default behavior for one specific <code>template&lt;typename T&gt;</code> parameter type?</p>
<p>Take five seconds to think about it before reading on.</p>
<p>I suspect the first thing that comes to mind for you is the same thing that came to mind for me — call <code>typeid(T)</code> inside the function to check the type of T, and branch on it:</p>
<pre><code>if (typeid(T) == typeid(std::string)) {
	// default behavior for string
}
</code></pre>
<p>Sorry, but no. It doesn't work, and things are nowhere near as simple as we'd like.</p>
<p>So what happens? Let's look at a complete example first.</p>
<pre><code>#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;

template&lt;typename T&gt;
class Printer
{
public:
    Printer() { }

    void DoIt(const T&amp; t)
    {
        if (typeid(T) == typeid(std::string)) {
            std::cout &lt;&lt; t &lt;&lt; std::endl;
        } else {
            std::cout &lt;&lt; "I don't know how to print" &lt;&lt; std::endl;
        }
    }
};

int main(int argc, char** argv)
{
    Printer&lt;std::string&gt; p;
    p.DoIt("WTF");

    Printer&lt;std::vector&lt;char&gt;&gt; p2;
    p2.DoIt({'W', 'T', 'F'});

    return 0;
}
</code></pre>
<p>Compile it:</p>
<pre><code>% clang++ SFINAE.cpp -std=c++11
SFINAE.cpp:14:23: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream&lt;char&gt;') and 'const std::vector&lt;char, std::allocator&lt;char&gt; &gt;')
            std::cout &lt;&lt; t &lt;&lt; std::endl;
            ~~~~~~~~~ ^  ~
</code></pre>
<p>The compiler tells us it can't call <code>std::cout &lt;&lt; t &lt;&lt; std::endl</code> — <code>t</code> is a <code>std::vector&lt;char&gt;</code>.</p>
<p>By now you can probably see it: on line 14 of the example above, the compiler instantiated the template with <code>std::vector&lt;char&gt;</code>, and the instantiated <code>Printer</code> looks like this:</p>
<pre><code>class Printer
{
public:
    Printer() { }

    void DoIt(const std::vector&lt;char&gt;&amp; t)
    {
        if (typeid(std::vector&lt;char&gt;) == typeid(std::string)) {
            std::cout &lt;&lt; t &lt;&lt; std::endl;
        } else {
            std::cout &lt;&lt; "I don't know how to print" &lt;&lt; std::endl;
        }
    }
};
</code></pre>
<p>The <code>if</code> on line 8 can never be true, but the compiler isn't that clever. All it sees is that you're trying to stream a <code>std::vector&lt;char&gt;</code> into <code>std::cout</code>, and that of course doesn't work.</p>
<p>You might be thinking: if the compiler were smart enough to eliminate a branch that can never execute at compile time, wouldn't that solve it? Let's set that aside for now, and look at how to solve this under C++11 instead. In other words: how do we implement a "compile-time if"?</p>
<p>Another idea comes to mind —</p>
<p>how do we get something like "partial specialization" for a class member function?</p>
<p>Here's the correct answer up front. Don't close the tab yet; I'll walk through it.</p>
<pre><code>class Printer
{
public:
    Printer() {
    }

    template &lt;typename U = T&gt;
    void
    DoIt(const T&amp; t, typename std::enable_if&lt;std::is_same&lt;U, std::string&gt;::value, void&gt;::type * = nullptr)
    {
        std::cout &lt;&lt; t &lt;&lt; std::endl;
    }

    template &lt;typename U = T&gt;
    void
    DoIt(const T&amp; t, typename std::enable_if&lt;!std::is_same&lt;U, std::string&gt;::value, void&gt;::type * = nullptr)
    {
        std::cout &lt;&lt; "I don't know how to print" &lt;&lt; std::endl;
    }
};
</code></pre>
<p>Let's start with the title of this post. SFINAE stands for "Substitution failure is not an error".</p>
<h2>typename</h2>
<p><a href="http://feihu.me/blog/2014/the-origin-and-usage-of-typename/">http://feihu.me/blog/2014/the-origin-and-usage-of-typename/</a></p>
<h2>SFINAE</h2>
<p><a href="https://zhuanlan.zhihu.com/p/21314708">https://zhuanlan.zhihu.com/p/21314708</a></p>
<h2>immediate context</h2>
<p><a href="https://codeday.me/en/qa/20190306/13897.html">https://codeday.me/en/qa/20190306/13897.html</a></p>
<h2>std::enable_if_</h2>
]]></content:encoded>
            <author>Yingjie Ye</author>
        </item>
        <item>
            <title><![CDATA[The Curse of Productivity]]></title>
            <link>https://yyj.us/posts/the-curse-of-productivity/</link>
            <guid isPermaLink="false">https://yyj.us/posts/the-curse-of-productivity/</guid>
            <pubDate>Thu, 03 Oct 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[A year after buying this domain to blog on, without having written a single post, namesilo came asking me to renew. Paying that $7.99 stung...]]></description>
            <content:encoded><![CDATA[<h3>1. The Prefix</h3>
<p>A year after buying this domain to blog on, without having written a single post, namesilo came asking me to renew. Paying that $7.99 stung a little — I'd sat on it for a year and done nothing with it.</p>
<h3>2. The Curse</h3>
<p>Setting aside my questionable writing, there were a few moments this past year when I actually felt the urge to write something. I even started a couple of times, but every one of them died on the vine. Looking back at why: at some point I started caring more about how much productivity my tools could give me than about actually producing anything. Tools that don't fit your hand make production cost more mental energy, and that makes you not want to produce at all. This chart from Reddit's vim board captures the state perfectly:</p>
<p><img src="https://yyj.us/_astro/vim-time-spent.I214v2n9_roqHH.webp" alt="" /></p>
<p>There are upsides and downsides to living like this. Take blogging:</p>
<p>Cons: every one of those urges this year got dropped because I didn't have a tool I was happy with. This time, after the renewal stung, I finally found one I like — Ulysses — and that's the only reason I could write this filler piece in the middle of a busy schedule (I wasn't busy; the filler part is true). Though inserting images is still not a smooth experience (</p>
<p>Pros: this tool also made me realize that collecting notes and organizing notes don't have to happen in the same app. So I'm dropping the extremely buggy Wiz Note I've been using and switching to Ulysses + Evernote. Here's hoping for a great leap forward in productivity (wait, that doesn't sound right</p>
<h3>3. The Productivity</h3>
<p>Section 2 was originally titled <code>Curse of Productivity</code>. Worried I'd misspelled something, I googled it — and found Observer's article <a href="https://observer.com/2014/02/the-curse-of-productivity-when-optimization-holds-you-back/">The Curse of Productivity</a>, which describes roughly the same state I was in. So I just renamed the whole post to match. It cites the <a href="https://en.wikipedia.org/wiki/Pareto_principle">Pareto principle</a>: 20% of the time gets you 80% of the productivity gain, and the remaining 20% of the gain costs the other 80% of the time — to the point where the time you save from being more productive may not even cover the time you spent getting there. I feel this in my bones. 80% of the time I've spent configuring vim went toward chasing that last 20%.</p>
<p>The article also argues that being too efficient makes you less creative. I don't buy that one. If higher productivity lowers the mental energy a task demands, then you have more mental energy left over for the creative things.</p>
<h3>4. The End</h3>
<p>This went downhill from the title, but that's enough rambling. Here's hoping I actually produce more this year — <a href="https://news.ycombinator.com/item?id=20781463">Consume less, create more</a>!</p>
<blockquote>
<p>Look at this post — still writing about productivity!</p>
</blockquote>
]]></content:encoded>
            <author>Yingjie Ye</author>
        </item>
    </channel>
</rss>