この(作成された)質問は、最初はパズルとして定式化され、問題をより迅速に確認するのに役立つ可能性のある詳細の一部を隠しています。下にスクロールして、より単純な [〜#〜] 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
_の出力が開始されます( 証明は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
は、1u
テンプレート引数のstd::bitset
に昇格されるtrue
に評価されます。このstd::bitset
は~n & 255
で初期化され、oldmode
と等しいかどうかがチェックされます。 std::bitset
には、oldmode
から一時的なstd::bitset<1>
を構築できる非明示的なコンストラクターがあるため、この最後のステップは有効です。
1 この場合、かなり微妙な構文解析のあいまいさの規則のため、this->bitset
を括弧で囲む必要があることに注意してください。詳細については、 テンプレートに依存するベースメンバーが適切に解決されない を参照してください。
はい、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;
を使用しないでください
- なぜこれが起こるのですか?
派生クラスの場合、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
- 回答後、この質問のタイトルは何にすべきですか?
「テンプレート基本クラスの非依存名にアクセスする方法は?」
これは本当にクールな例です!!! :)
私は思う-これは何が起こっているのか:
bitset < 32 && 63 >(~n & 255)
構文解析はbitset
を構成します