问题描述
原始版本(拼图游戏)
我有这段输出0
的代码:
Original (a-la puzzle) version
I have this piece of code that outputs 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;
}
但是,当我将函数foo()
从B
移到D
时,它开始输出1
(证明在Coliru上).
However, when I move the function foo()
from B
to D
it starts outputting 1
(proof is on Coliru).
为什么会这样?
#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()?
}
推荐答案
这就是为什么您永远不要using namespace std;
This is why you should never using namespace std;
bool foo(T n, string s)
{
return bitset < 32
&& 63 > (~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
那个bitset
不是您想的那样.因为B<T>
是从属基类,所以成员从不合格的查找中隐藏.因此,要访问bitset
,您需要通过this
对其进行访问,或对其进行明确限定(请参阅以获取更多详细信息):
That bitset
isn't what you think it is. Because B<T>
is a dependent base class, members are hidden from unqualified lookup. So to access bitset
, you need to access it through this
, or explicitly qualify it (see here for more details):
(this->bitset)
B<T>::bitset
因为在派生情况下bitset
没有命名B<T>::bitset
,这意味着什么?好吧,因为您编写了using namespace std;
,所以它实际上是std::bitset
,其余的表达式恰好是有效的.这是发生了什么:
Because bitset
doesn't name B<T>::bitset
in the derived case, what could it mean? Well, because you wrote using namespace std;
, it's actually std::bitset
, and the rest of your expression just so happens to be valid. Here's what happens:
bool foo(T n, string s)
{
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
32 && 63
的计算结果为true
,对于std::bitset
模板参数,其被提升为1u
.此std::bitset
用~n & 255
初始化,并用oldmode
检查是否相等.最后一步是有效的,因为std::bitset
具有非显式构造函数,该构造函数允许从oldmode
构造临时std::bitset<1>
.
The 32 && 63
evaluates to true
, which is promoted to 1u
for the std::bitset
template argument. This std::bitset
is initialized with ~n & 255
, and is checked for equality with oldmode
. This last step is valid because std::bitset
has a non-explicit constructor which allows a temporary std::bitset<1>
to be constructed from oldmode
.
注意,在这种情况下,由于一些非常清晰的解析歧义规则,我们需要在this->bitset
上加上括号.有关详细信息,请参见依赖模板的基础成员未正确解析.
Note that we need to parenthesise this->bitset
in this case due to some pretty subtle parsing disambiguity rules. See Template dependent base member is not resolved properly for details.
这篇关于将成员函数从基类移到派生类不会明显破坏程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!