問題描述
在下面的例子中,A
有一個成員 typedef Instantiate
,它導致 B
的實例化.
In the following example, A
has a member typedef Instantiate
which causes the instantiation of B<A>
.
template<typename T>
struct B
{
typedef typename T::Before Before; // ok
typedef typename T::After After; // error: no type named 'After' in 'A<int>'
};
template<typename T>
struct A
{
typedef int Before;
typedef typename B<A>::After Instantiate;
typedef int After;
};
template struct A<int>; // instantiate A<int>
我嘗試過的所有編譯器都報告說,雖然 A::Before
可見,但 A::After
不可見.這種行為是否符合標準?如果是這樣,標準在哪里指定在 B<A>
的實例化過程中 A
中的哪些名稱應(yīng)該是可見的?
All the compilers I've tried report that, while A::Before
is visible, A::After
is not. Is this behaviour compliant with the standard? If so, where does the standard specify which names in A
should be visible during instantiation of B<A>
?
如果依賴名稱是在模板實例化點查找",那么在名稱由模板參數(shù)(例如 T::After
)限定的情況下,這意味著什么?
If dependent names are "looked up at the point of the template instantiation", what does this mean in the scenario of a name qualified by a template parameter such as T::After
?
請注意,當 A 不是模板時會發(fā)生相同的行為:
Note that the same behaviour occurs when A is not a template:
template<typename T>
struct B
{
typedef typename T::Before Before; // ok
typedef typename T::After After; // error: no type named 'After' in 'A'
};
struct A
{
typedef int Before;
typedef B<A>::After Instantiate;
typedef int After;
};
.. 和 G++ 接受以下內(nèi)容,但 Clang 不接受:
.. and G++ accepts the following, but Clang does not:
template<typename T>
struct B
{
static const int value = 0;
static const int i = T::value; // clang error: not a constant expression
};
struct A
{
static const int value = B<A>::value;
};
在閱讀了 C++03 標準之后:
After some reading of the C++03 standard:
[temp.dep.type] 一個類型是依賴的,如果它是一個模板參數(shù)
[temp.dep.type] A type is dependent if it is a template parameter
因此 T
是依賴的.
[temp.res] 在查找模板定義中使用的名稱的聲明時,通常的查找規(guī)則用于非依賴名稱.依賴模板參數(shù)的名稱查找被推遲到實際模板參數(shù)已知.
[temp.res] When looking for the declaration of a name used in a template definition, the usual lookup rules are used for nondependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known.
T::After
的查找因此被推遲,直到 T
的參數(shù)已知.
The lookup of T::After
is therefore postponed until the argument for T
is known.
[temp.inst] 除非已顯式實例化類模板特化……當在需要完全定義的對象類型的上下文中引用特化時,類模板特化會被隱式實例化.
[temp.inst] Unless a class template specialization has been explicitly instantiated ... the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type.
因此 A<int>::Instantiate
的聲明需要 B<A>
的實例化(因為它用于嵌套名稱說明符.)
Therefore the declaration of A<int>::Instantiate
requires the instantiation of B<A>
(because it is used in a nested-name-specifier.)
A<int>::After
在 A<int>::Instantiate
的聲明點不可見,所以編譯器的行為是有道理的 -但我在 C++03 中沒有看到任何明確描述這種行為的內(nèi)容.最接近的是這個有點模糊的段落:
A<int>::After
is not visible at the point of declaration of A<int>::Instantiate
, so the behaviour of the compiler makes sense - but I haven't seen anything in C++03 that explicitly describes this behaviour. The closest thing was this somewhat vague paragraph:
[temp.dep.res]在解析依賴名稱時,會考慮來自以下來源的名稱:
[temp.dep.res] In resolving dependent names, names from the following sources are considered:
——在模板定義點可見的聲明.
— Declarations that are visible at the point of definition of the template.
推薦答案
typename T::Before
是否有效在規(guī)范中沒有明確說明.它是缺陷報告的主題(因為可以非常合理地閱讀標準來禁止它):http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287.
Whether typename T::Before
is valid is not explicitly said by the spec. It is subject of a defect report (because the Standard can very reasonably be read to forbid it): http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 .
typename T::After
是否無效也可以很合理地被規(guī)范讀取為真的,實際上它有相當多的意義(并且前面提到的 DR 仍然保持格式錯誤).因為您有一個類 A
的實例化,它在成員 Baz
具有的期間引用了另一個類 A
尚未聲明,這會引用回 A<Foo>::Bar
.在非模板的情況下,這也是格式錯誤的(嘗試暫時忘記"您正在處理模板:B<A>::After
的查找肯定已完成A
模板被完全解析,但不是在它的具體實例化完全創(chuàng)建之后.實際上是它的實例化做參考!)
Whether typename T::After
is invalid can also very reasonably be read to be true by the spec, and actually it makes quite a bit of sense (and aforementioned DR still keeps it ill-formed). Because you have an instantiation of a class A<Foo>
, which references another class A<Bar>
during a period where a member Baz
has not yet been declared, and that makes a reference back to A<Foo>::Bar
. That is ill-formed in the case of non-templates aswell (try to "forget" for a moment that you are dealing with templates: surely the lookup of B<A>::After
is done after the A
template was completely parsed, but not after the specific instantiation of it was completely created. And it is the instantiation of it that actually will do the reference!).
struct A {
typedef int Foo;
typedef A::Foo Bar; // valid
typedef A::Baz Lulz; // *not* valid
typedef int Baz;
};
這篇關(guān)于實例化模板時,其不完整參數(shù)類型的成員是否應(yīng)該可見?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!