原始(a-la拼图)版本
我有这段输出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
(proof is on Coliru)。为什么会这样?
MCVE版本
Live 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;
bool foo(T n, string s)
{
return bitset < 32
&& 63 > (~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
那个
bitset
不是您想的那样。因为B<T>
是一个依赖的基类,所以从不合格的查找中隐藏了成员。因此,要访问bitset
,您需要通过this
1对其进行访问,或对其进行显式限定(有关更多详细信息,请参见here):(this->bitset)
B<T>::bitset
因为在派生的情况下
bitset
没有命名B<T>::bitset
,这意味着什么?好吧,因为您编写了using namespace std;
,实际上是std::bitset
,其余的表达式恰好是有效的。这是发生了什么:bool foo(T n, string s)
{
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
32 && 63
的计算结果为true
,对于1u
模板参数,该值提升为std::bitset
。此std::bitset
使用~n & 255
初始化,并使用oldmode
检查是否相等。最后一步是有效的,因为std::bitset
具有一个非显式的构造函数,该构造函数允许从std::bitset<1>
构造一个临时的oldmode
。1注意,在这种情况下,由于一些非常清晰的解析歧义规则,我们需要在
this->bitset
上加上括号。有关详细信息,请参见Template dependent base member is not resolved properly。关于c++ - 将成员函数从基类移动到派生类不会明显破坏程序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40462612/