Разве это незаконно, получить `sizeof` нестатический член структуры, вложенной в шаблон шаблона?

В clang/llvm 3.6.2 следующий код приводит к ошибке компиляции при компиляции с помощью std=c++11:

template <typename T=void>
class bar
{
public:
    struct foo
    {
        int array[10];
    };

    int baz()
    {
        return sizeof(foo::array);
    }
};

int main(void)
{
    bar<> b;
    return b.baz();
}

Вызов командной строки:

$ clang++ -std=c++11 nonstatic.cpp -o nonstatic
nonstatic.cpp:12:28: error: invalid use of non-static data member 'array'
        return sizeof(foo::array);
                      ~~~~~^~~~~
nonstatic.cpp:20:14: note: in instantiation of member function
'bar<void>::baz' requested here
    return b.baz();

Если я изменю bar больше не шаблон, как в

class bar
{
public:
    struct foo
    {
        int array[10];
    };

    int baz()
    {
        return sizeof(foo::array);
    }
};

int main(void)
{
    bar b;
    return b.baz();
}

тогда код компилируется чисто. Следует отметить, что GCC 5.2.1 принимает обе версии под std=c++11. Также следует отметить, что перемещение array в тело шаблона охватывающего класса (но оставление его в качестве шаблона) также приводит к тому, что clang принимает это.

Какое поведение верно по отношению к стандарту? Является ли это ошибкой в ​​GCC, clang или обоих?

(Я задал тот же вопрос для пользователей cfe, но пока не получил ответа).

Ответы

Ответ 1

Это, безусловно, ошибка clang; операнд вашего выражения sizeof является id-выражением, обозначающим нестатический элемент данных, поэтому выполняется [expr.prim.general]/13. Здесь приведен пример:

template<class T> struct M { int f() { return sizeof(T::x); } };
struct S { int x; };
int main() { return M<S>{}.f(); }

Ошибка возникает при доступе к члену зависимого типа в необоснованном контексте в методе экземпляра шаблона. Clang-реализация правила n2253, позволяющего использовать нестатические члены данных в неоценимом контексте (и более поздние улучшения), выглядит довольно хрупкой и плохо взаимодействует с шаблонами; аналогичная (хотя и явная) ошибка http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20151019/141535.html.

Я не могу найти никаких указаний на то, что об этом уже сообщалось Clang Bugzilla; вы можете открыть новую ошибку.

В зависимости от вашей ситуации обходные методы могут включать в себя перемещение вычислений статического типа и значения вне метода экземпляра; в частности даже создание функции baz a static является достаточным, чтобы убедить clang принять ваш код.