spécialisation de gabarit de membre et son étendue
-
03-07-2019 - |
Question
Il me semble que C ++ n'autorise pas la spécialisation de modèle de membre dans une étendue autre que l'espace de noms et l'étendue globale (erreur MS VSC ++ C3412). Mais pour moi, il est logique de spécialiser le modèle de membre principal d'une classe de base dans la classe dérivée, car c'est ce que font les classes dérivées - spécialiser les éléments de la classe de base. Par exemple, considérons l'exemple suivant:
struct Base
{
template <class T>
struct Kind
{
typedef T type;
};
};
struct Derived : public Base
{
/* Not Allowed */
using Base::Kind;
template <>
struct Kind <float>
{
typedef double type;
};
};
int main(void)
{
Base::Kind<float>::type f; // float type desired
Derived::Kind<float>::type i; // double type desired but does not work.
}
Ma question est: pourquoi est-ce interdit?
La solution
Je comprends ce que vous essayez de faire, mais vous ne le faites pas correctement. Essayez ceci:
struct Base{};
struct Derived{};
// Original definition of Kind
// Will yield an error if Kind is not used properly
template<typename WhatToDo, typename T>
struct Kind
{
};
// definition of Kind for Base selector
template<typename T>
struct Kind<Base, T>
{
typedef T type;
};
// Here is the inheritance you wanted
template<typename T>
struct Kind<Derived, T> : Kind<Base, T>
{
};
// ... and the specialization for float
template<>
struct Kind<Derived, float>
{
typedef double type;
};
Autres conseils
Ma question est: pourquoi est-ce interdit?
D'après ma copie du projet, il apparaît que ce qui suit place la restriction ci-dessus:
Dans une déclaration de spécialisation explicite pour un modèle de classe, un membre d'un modèle de classe ou un membre de classe template, le nom de la classe explicitement spécialisée doit être un simple-template-id.
La solution consiste à spécialiser la classe englobante.
Je vais "ignorer" les spécifications standard et essayez un argument logique:
Si vous avez deux classes:
class A
{
struct S { };
};
class B: public A
{
struct S { };
};
A :: S et B :: S sont deux types différents. En étendant la logique aux spécialisations de modèle, lorsque vous essayez de spécialiser une classe interne déclarée dans la classe de base par le biais d'une classe interne dans une classe dérivée, vous essayez en fait de définir un type différent, avec le même nom (mais une autre portée de dénomination).