Ce (fait) question a d'abord été formulé comme un puzzle, cacher certains détails qui pourraient aider à voir le problème plus rapidement. Faites défiler vers le bas pour la plus simple MCVE version.
D'origine (un-la de puzzle) version
J'ai ce bout de code qui génère
0
:#include <iostream> #include <regex> using namespace std; regex sig_regex("[0-9]+"); bool oldmode = false; template<class T> struct B { T bitset; explicit B(T flags) : bitset(flags) {} bool foo(T n, string s) { return bitset < 32 // The mouth is not full of teeth && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches } }; template<class T> struct D : B<T> { D(T flags) : B<T>(flags) {} }; int main() { D<uint64_t> d(128 | 16 | 1); cout << d.foo(7, "123") << endl; }
Cependant, quand je bouge la fonction
foo()
deB
deD
il commence à sortir des1
(la preuve est sur Coliru).Pourquoi est-ce arrivé?
MCVE version
#include <iostream> #include <bitset> using namespace std; template<class T> struct B { T bitset{0}; bool foo(int x) { return bitset < 32 && 63 > (x + 1) == x % 2; } }; template<class T> struct D : B<T> { bool bar(int x) // This is identical to B<T>::foo() { return bitset < 32 && 63 > (x + 1) == x % 2; } }; int main() { D<uint64_t> d; cout << d.foo(1) << endl; // outputs 1 cout << d.bar(1) << endl; // outputs 0; So how is bar() different from foo()? }
Réponses
Trop de publicités?C'est pourquoi vous devriez ne jamais using namespace std;
bool foo(T n, string s)
{
return bitset < 32
&& 63 > (~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
Qu' bitset
n'est pas ce que vous pensez qu'elle est. Parce qu' B<T>
est un dépendant de la classe de base, les membres sont cachés non qualifiés de recherche. Afin d'accéder bitset
, vous devez avoir accès par l'entremise this
1, ou explicitement qualifier (voir ici pour plus de détails):
(this->bitset)
B<T>::bitset
Parce qu' bitset
n'a pas de nom B<T>::bitset
dans le dérivé cas, que pourrait-il dire? Eh bien, parce que vous avez écrit using namespace std;
, std::bitset
, et le reste de votre expression se trouve juste à être valide. Voici ce qui arrive:
bool foo(T n, string s)
{
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
L' 32 && 63
évalue true
, ce qui est promu 1u
de la std::bitset
argument de modèle. Cette std::bitset
est initialisé avec ~n & 255
, et est vérifié pour l'égalité avec l' oldmode
. Cette dernière étape est valide parce qu' std::bitset
a un non-explicite du constructeur qui permet temporairement std::bitset<1>
à être construit à partir d' oldmode
.
1 Notez que nous devons parenthesise this->bitset
dans ce cas en raison de certaines assez subtile analyse disambiguity règles. Voir Modèle dépendant de la base de membre n'est pas réglée correctement pour plus de détails.
Oui, car bitset
sera interprété comme un nom non dépendant et il existe un modèle nommé std::bitset<T>
. Il sera donc analysé comme suit:
template<class T>
struct D : B<T>
{
D(T flags) : B<T>(flags) {}
bool foo(T n, string s)
{
return ((std::bitset < 32 && 63 > (~n & 255)) == oldmode)
&& regex_match(s, sig_regex);
}
};
Vous devez le faire comme ceci:
template<class T>
struct D : B<T>
{
D(T flags) : B<T>(flags) {}
bool foo(T n, string s)
{
// or return B<T>::bitset
return (this->B<T>::bitset < 32) // The mouth is not full of teeth
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
}
};
ou mieux, n'utilisez pas using namespace std;
- Pourquoi est-ce arrivé?
Pour la classe dérivée,
B<T>
n'est pas un non dépendantes de la classe de base, il ne peut pas être déterminée sans connaître l'argument de modèle. Etbitset
est un non dépendantes nom, qui ne sera pas regardé en dépendant de la classe de base. Au lieu de cela,std::bitset
est utilisé ici (en raison de l'using namespace std;
). Ainsi, vous obtiendrez:return std::bitset<32 && 63>(~n & 255) == oldmode && regex_match(s, sig_regex);
Vous pourriez faire le nom d'
bitset
à charge; car dépendante de noms peuvent être consultées uniquement au moment de l'instanciation, et à ce moment exact de la base de la spécialisation qui doit être explorée. Par exemple:return this->bitset < 32 // The mouth is not full of teeth // ~~~~~~ && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches
ou
return B<T>::bitset < 32 // The mouth is not full of teeth // ~~~~~~ && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches
ou
using B<T>::bitset; return bitset < 32 // The mouth is not full of teeth && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches
- Quel devrait être le titre de cette question, après c'est une réponse?
"Comment accéder à la non dépendantes des noms dans la base de modèle de classe?"