У меня есть шаблон класса, который содержит другой шаблон класса, а внутренний шаблон имеет явную специализацию:
template <typename Outer>
struct ContainingClass {
template <typename T>
struct Rule {
Rule(T value);
// ... other members ...
};
template <>
struct Rule<void> {
Rule();
// ... different members than the non-void Rule<T> ...
};
};
Я определил конструкторы как для универсального, так и специализированного Rule
:
template <typename Outer>
template <typename T>
ContainingClass<Outer>::Rule<T>::Rule(T value) { }
template <typename Outer>
ContainingClass<Outer>::Rule<void>::Rule() { }
Но Clang не нравится конструктор специализированного класса:
error: nested name specifier 'ContainingClass<Outer>::Rule<void>::' for declaration does not refer into a class, class template or class template partial specialization
ContainingClass<Outer>::Rule<void>::Rule() { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
Я озадачен этим, потому что он "ссылается на" ContainingClass<Outer>
, что является класс (экземпляр шаблона класса ContainingClass
).Я подозреваю, что мне нужно что-то изменить в синтаксисе для этого, но не ясно, что.Как я могу определить этот конструктор?
(Он работает, если я удаляю ContainingClass
и помещаю Rule
в область имен, но мне нужно, чтобы в Rule
были другие вещи, которые зависят от типа Outer
Я мог бы дать Rule
свой собственный Outer
параметр шаблона, но это сделает вещи более неуклюжими для кода, использующего этот класс, поэтому я хотел бы избежать его, если это возможно. И я знаю, что могу определить конструкторвстроенный в тело класса Rule
, но я хотел бы понять, почему отдельное определение не работает.)
В случае, если это имеет значение, я использую как Clang 8.0 в Ubuntu 19.04, так и Apple«clang-1001.0.46.4» на Mac.(Я также попробовал GCC 8.3 в Ubuntu, но в другом месте это не помогло из-за ошибки GCC # 85282 - «явная специализация в области без пространства имен» в определении самого struct Rule<void>
.)
Отредактировано для уточнения: Моя ошибка не в том, что специализация template <> struct Rule<void>
в пределах ContainingClass
.Это предмет ограничения C ++ 14 ( дефект CWG 727 ), который обходится путем добавления фиктивного параметра шаблона, чтобы шаблон был только частично, а не полностью специализированным.Я считаю, что ограничение было снято в C ++ 17, и специализация самого класса Rule
прекрасно работает в Clang (хотя в GCC есть ошибка).Так что я думаю, что обходной путь фиктивного параметра не является правильным решением здесь - но, пожалуйста, скажите мне, если я ошибаюсь, и все еще есть ограничения на это в C ++ 17.