这个(化妆)问题最初是作为一个谜题而隐藏的 一些可能有助于更快地查看问题的细节。向下滚动 对于更简单的MCVE版本。
我有这段代码输出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)。
为什么会这样?
#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()?
}
答案 0 :(得分:90)
这就是为什么你永远不应该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。
答案 1 :(得分:18)
是的,因为bitset
将被解释为非依赖名称,并且有一个名为std::bitset<T>
的模板,因此,它将被解析为:
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);
}
};
你需要这样做:
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
}
};
或更好,请勿使用using namespace std;
答案 2 :(得分:8)
- 为什么会这样?
醇>
对于派生类,B<T>
不是非依赖基类,不能在不知道模板参数的情况下确定它。 bitset
是一个非依赖名称,不会在依赖基类中查找。相反,此处使用std::bitset
(因为using namespace std;
)。所以你得到:
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
您可以将名称bitset
视为依赖;因为只能在实例化时查找依赖名称,并且在那时必须知道必须探索的确切基本特化。例如:
return this->bitset < 32 // The mouth is not full of teeth
// ~~~~~~
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
或
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
或
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
- 在回答之后,这个问题的标题应该是什么?
醇>
&#34;如何访问模板基类中的非依赖名称?&#34;
答案 3 :(得分:3)
这是一个非常酷的例子!!! :)
我想 - 发生了什么事:
bitset < 32 && 63 >(~n & 255)
解析为构建我bitset