Понимание частичной специализации унаследованных вложенных шаблонов классов

Этот вопрос связан с предыдущий вопрос& в котором упоминался отчет об ошибке для gcc (предположительно исправленный в gcc 4.5.0) и касающийся некоторых особенностей частичной специализации шаблона вложенного класса.

Моя установка в том, что у меня есть класс Base с вложенным шаблоном класса Inner это частично специализируется на char (используя трюк с фиктивным параметром, потому что явная спецификация не разрешена в классе).

#include <type_traits>
#include <iostream>
#include <ios>

struct Base
{
// dummy template parameter...
template<class U, class _ = void> struct Inner: std::true_type {};

// ... to allow in-class partial specialization
template<class _> struct Inner<char, _>: std::false_type {};
};

Я сейчас определяю Derived класс для которого я еще хочу специализироваться Innerчто по какой-то странной причине не может быть сделано в классе (даже если это все еще частичная специализация).

struct Derived
:
Base
{
// cannot partially specialize Inner inside Derived...
//template<class _>
//struct Inner<int, _>: std::false_type {};
};

// ... but specializing Derived::Inner at namespace scope, also specializes it for Base::Inner
template<class _> struct Derived::Inner<int, _>: std::false_type {};

Первый вопрос: почему я должен частично специализироваться Derived::Inner в области имен пространства?

Но самое странное то, что когда я называю различные частичные специализации Inner от обоих Base а также Derivedчастичная специализация для int что я сделал только для Derivedтакже относится к Base,

int main()
{
std::cout << std::boolalpha << Base::Inner<float>::value << "\n";
std::cout << std::boolalpha << Derived::Inner<float>::value << "\n";

std::cout << std::boolalpha << Base::Inner<char>::value << "\n";
std::cout << std::boolalpha << Derived::Inner<char>::value << "\n";

std::cout << std::boolalpha << Base::Inner<int>::value << "\n";      // huh???
std::cout << std::boolalpha << Derived::Inner<int>::value << "\n";   // OK
}

Второй вопрос: почему Base::Inner<int>::value равно falseхотя бы только Derived::Inner<int> был частично специализирован?

Онлайн пример использования gcc 4.8.0. Я специально ищу цитаты из Стандарта, которые объясняют это поведение.

1

Решение

Частичная специализация должна переопределить то же имя, что и основной шаблон, для которого оно предоставляет альтернативное определение.

Когда ты пишешь struct Inner в рамках Derivedобъявляешь Derived::Inner, Base::Inner отличное имя от Derived::Inner и поэтому объявляет другой класс. Не возможно специализироваться Base::Inner с декларацией, которая объявляет Derived::Inner,

Когда ты пишешь Derived::Inner в области имен пространства поиск имени разрешает это имя в Base::Inner — все специализации одного и того же класса: Base::Inner, даже если вы относитесь к ним как Derived::Inner,

Из стандарта:

[Temp.class.spec]

Частичная специализация шаблона класса обеспечивает альтернативное определение шаблона, который используется вместо основного определения, когда аргументы в специализации совпадают с аргументами, указанными в частичной специализации.

1

Другие решения

Специализированные шаблоны не являются частью полиморфизма.

Вы на самом деле объявляете тип. Таким образом, любой модуль компиляции, который может видеть производный заголовочный файл с реализацией для специализации шаблона, будет использовать эту специализацию для вложенного класса шаблона.

Компилятор пытается найти класс наилучшего соответствия и всегда будет выбирать специализированный тип по умолчанию. Так что даже если вы попытаетесь получить доступ к области действия базового типа, это все тот же класс.

То же самое произошло бы, если бы вы специализировали класс шаблона в любой другой части вашего кода. Компилятор выберет наиболее подходящую специализацию, если ее нет, он примет «значение по умолчанию».

1

По вопросам рекламы [email protected]