различное поведение активатора в разных контекстах в шаблонах классов

Почему поведение такое разное? Версия #if 1 успешно (что странно) компилируется и выдает ожидаемый результат в stdout, но версия с #if 0 этого не делает:

#include <iostream>
#include <type_traits>

#include <cstdlib>

template< typename T >
class X
{

    struct B {};

public :

    struct U : B {};

};

template< typename T >
struct Y
{

    using X_type = X< T >;

    template< typename D,
              typename = typename std::enable_if< std::is_base_of< typename X_type::B, D >::value >::type >
    void operator () (D const &) const
    {
        std::cout << "allowed only for derived from B" << std::endl;
    }

};

template< typename T >
struct Z
{

    using X_type = X< T >;

    template< typename D >
    auto
    operator () (D const &) const
    -> typename std::enable_if< std::is_base_of< typename X_type::B, D >::value >::type
    {
        std::cout << "allowed only for derived from B!" << std::endl;
    }

};

int main()
{
    using T = struct W; // not matters
    using X_type = X< T >;
    using U = typename X_type::U;
#if 0
    using V = Y< T >;
#else
    using V = Z< T >;
#endif
    V v;
    v(U());
    return EXIT_SUCCESS;
}

Это вызывает ошибку (по существу, 'B' is private в соответствии с моими ожиданиями (фактически) для обоих случаев):

<stdin>: In function 'int main()':
<stdin>:60:10: error: no match for call to '(V {aka Z<main()::W>}) (U)'
<stdin>:34:8: note: candidate is:
<stdin>:41:5: note: template<class D> typename std::enable_if<std::is_base_of<typename X<T>::B, D>::value>::type Z<T>::operator()(const D&) const [with D = D; T = main()::W]
<stdin>:41:5: note:   template argument deduction/substitution failed:
<stdin>: In substitution of 'template<class D> typename std::enable_if<std::is_base_of<typename X<T>::B, D>::value>::type Z<T>::operator()(const D&) const [with D = D; T = main()::W] [with D = X<main()::W>::U]':
<stdin>:60:10:   required from here
<stdin>:10:12: error: 'struct X<main()::W>::B' is private
<stdin>:41:5: error: within this context

Выход g++ -v содержит следующую строку:

gcc version 4.8.1 (rev3, Built by MinGW-builds project) 

Я ожидаю, что B вообще недоступен ниоткуда, кроме X.

Проблема имеет место исключительно только для шаблонов классов, но не для чистых классов (здесь мы имеем две одинаковые проблемы, потому что оба варианта не надо компилировать, а компилируют).


person Tomilov Anatoliy    schedule 16.10.2013    source источник
comment
Я ожидаю, что B вообще недоступен ниоткуда, кроме X.   -  person Tomilov Anatoliy    schedule 16.10.2013
comment
Я предполагаю, что причина в аргументе по умолчанию, он оценивается только в том случае, если (и когда) он используется.   -  person dyp    schedule 16.10.2013
comment
Неназванный аргумент по умолчанию используется (оценивается) в обоих случаях, будьте уверены. Попробуйте позвонить v(0); вместо v(U());.   -  person Tomilov Anatoliy    schedule 16.10.2013
comment
К сожалению, я снова компилировал с clang++ 3.4 ;), где обе версии не работают.   -  person dyp    schedule 16.10.2013
comment
@DyP И это то, чего я с радостью ожидаю =).   -  person Tomilov Anatoliy    schedule 16.10.2013
comment
С учетом основных положений stackoverflow.com/questions/19378749 для себя могу сделать вывод, что clang проект обогнал gcc проект.   -  person Tomilov Anatoliy    schedule 16.10.2013
comment
В плане соответствия, наверное. Возможно, обратите внимание на эту и связанные с ней ошибки.   -  person dyp    schedule 16.10.2013
comment
@DyP Это очень похоже на суть вопроса. Спасибо.   -  person Tomilov Anatoliy    schedule 16.10.2013
comment
@DyP обратите внимание, что GCC компилирует оба варианта, если мы работаем с классами, а не с шаблонами классов.   -  person Tomilov Anatoliy    schedule 16.10.2013