考慮以下A定義模板內部類的類B:
struct A {
template<class = int>
struct B { };
};
我們可以使用下面的運算式來初始化inner B,其中typename是可選的:(Godbolt)
int main() {
A::template B<>();
typename A::template B<>();
}
我想用來concept檢測一個型別是否有一個模板內部類B:
template<class T>
concept C = requires {
typename T::template B<>();
};
static_assert(C<A>);
但是只有 Clang 接受了上面的代碼,GCC 和 MSVC 由于語法錯誤(Godbolt)拒絕了它:
<source>:8:27: error: expected ';' before '(' token
8 | typename T::template B<>();
| ^
| ;
如果我洗掉typename了的require條款:
template<class T>
concept C = requires {
T::template B<>();
};
MSVC 接受了它,但 Clang 和 GCC 會產生,static assertion failed因為他們認為運算式格式不正確(Godbolt):
<source>:11:15: note: because 'A' does not satisfy 'C'
static_assert(C<A>);
^
<source>:8:15: note: because 'T::template B<>()' would be invalid: 'A::B' instantiated to a class template, not a function template
T::template B<>();
^
我應該信任哪個編譯器?
uj5u.com熱心網友回復:
我對概念的理解是,如果要檢查此類情況,則必須使用復合陳述句。
struct A
{
template<class = int>
struct B { };
};
template<class T>
concept C = requires
{
{ typename T::template B<>() };
};
static_assert(C<A>);
我相信您不能在simple requirement子句中使用它,因為它T::template B<>是一個從屬名稱并且需要typename前面的關鍵字,因為概念本身是一個模板并且您處于未評估的背景關系中。
如果使用typename前面的關鍵字,則不再是asimple requirement而是變成了a type requirement。但是這個檢查型別的存在并不打算構建一個運算式來實體化型別。
因此,您最終會得到一個復合運算式,您可以typename在依賴模板中使用關鍵字獲取型別并執行該型別的默認初始化。
作為替代,如所示C2,你可以選擇在概念模板引數串列,它使您可以使用發現型別不包含此關鍵字的前期型別typename的simple requires clause。
我還添加了測驗用例,以通過“殺死”內部型別的默認建構式來查看概念失敗B。
struct A
{
template<class = int>
struct B { };
};
struct A2
{
template<class = int>
struct B { B()=delete; };
};
template<class T>
concept C = requires
{
{ typename T::template B<>() };
};
template<class T, typename Inner = typename T::template B<> >
concept C2 = requires
{
Inner();
};
static_assert(C<A>);
static_assert(C<A2>); // fails as expected
static_assert(C2<A>);
static_assert(C2<A2>); // fails as expected
上面的代碼適用于所有三個給定的編譯器:探索
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/386261.html
