Private member access in template substitution and SFINAE
<pre><code>class A { int a; };

template&lt;typename, typename = void&gt;
class test {};

template&lt;typename T&gt;
class test&lt;T,decltype(T::a)&gt; {};

int main() { test&lt;A&gt; a; }
</code></pre>

<p>The code above compiles without error on <code>clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)</code>, but fails to compile on <code>g++-5 (Ubuntu 5.4.1-2ubuntu1~16.04) 5.4.1 20160904</code> and <code>g++-6 (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901</code> with errors like this:</p>

<pre><code>main.cpp: In function ‘int main()’:
main.cpp:9:22: error: ‘int A::a’ is private within this context
 int main() { test&lt;A&gt; a; }
                      ^
main.cpp:1:15: note: declared private here
 class A { int a; };
</code></pre>

<p>In both cases I compiled with <code>-std=c++11</code>, but the effect is the same for <code>-std=c++14</code> and <code>-std=c++1z</code>.</p>

<p>Which compiler is correct here? I assumed that, at least since C++11, accessing private members during template substitution should trigger SFINAE, implying that clang is correct and gcc is not. Is there some additional rule I am unaware of?</p>

<p>For referencce, I am thinking of the note in §14.8.2/8 of the current standard draft N4606:</p>

<blockquote>
  <p>If a substitution results in an invalid type or expression, type
  deduction fails. An invalid type or expression is one that would be
  ill-formed, with a diagnostic required, if written using the
  substituted arguments. [ Note: If no diagnostic is required, the
  program is still ill-formed. Access checking is done as part of the
  substitution process. — end note ]</p>
</blockquote>

<p>Using a member function and a member function pointer instead is accepted by both compilers:</p>

<pre><code>class A { void a() {}; };

template&lt;typename, typename = void&gt;
class test {};

template&lt;typename T&gt;
class test&lt;T,decltype(&amp;T::a)&gt; {};

int main() { test&lt;A&gt; a; }
</code></pre>