Leo*_*eon 51 c++ templates namespaces c++11
这个(化妆)问题最初是作为一个谜题制定的,隐藏了一些可能有助于更快地看到问题的细节.向下滚动以查看更简单的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;
}
Run Code Online (Sandbox Code Playgroud)
然而,当我移动功能,foo()从B以D它开始输出1(证明是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()?
}
Run Code Online (Sandbox Code Playgroud)
Tar*_*ama 90
这就是你永远不应该的原因 using namespace std;
bool foo(T n, string s)
{
return bitset < 32
&& 63 > (~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
Run Code Online (Sandbox Code Playgroud)
这bitset不是你的想法.因为B<T>是依赖的基类,所以隐藏成员以进行非限定查找.因此,要访问bitset,您需要通过this1访问它,或明确限定它(有关详细信息,请参阅此处):
(this->bitset)
B<T>::bitset
Run Code Online (Sandbox Code Playgroud)
因为在派生的案例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);
}
Run Code Online (Sandbox Code Playgroud)
该32 && 63计算结果为true,这是晋升1u为std::bitset模板参数.这用std::bitset初始化~n & 255,并检查是否相等oldmode.最后一步是有效的,因为它std::bitset有一个非显式构造函数,允许构造临时std::bitset<1>构造函数oldmode.
1请注意,this->bitset由于一些非常微妙的解析歧义规则,我们需要在这种情况下使用括号.有关详细信息,请参阅模板相关基本成员未正确解析.
Dan*_*anh 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);
}
};
Run Code Online (Sandbox Code Playgroud)
你需要这样做:
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
}
};
Run Code Online (Sandbox Code Playgroud)
或更好,不要使用 using namespace std;
- 为什么会这样?
对于派生类,B<T>它不是非依赖的基类,如果不知道模板参数,则无法确定它.并且bitset是一个非依赖名称,不会在依赖基类中查找.相反,std::bitset在这里使用(因为using namespace std;).所以你会得到:
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
Run Code Online (Sandbox Code Playgroud)
你可以使名称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
Run Code Online (Sandbox Code Playgroud)
要么
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
Run Code Online (Sandbox Code Playgroud)
要么
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
Run Code Online (Sandbox Code Playgroud)
- 在回答之后,这个问题的标题应该是什么?
"如何访问模板基类中的非依赖名称?"
| 归档时间: |
|
| 查看次数: |
3304 次 |
| 最近记录: |