codingdir logo sitemap sitemap |
Home
PHP
C#
C++
ANDROID
JAVA
JAVASCRIPT
PYTHON

Where does the C++98 standard specify when a call to a static member is dependent within a template?


By : , Category : c++

Dependent names are defined in 14.6.2. gcc complains about I<sizeof(f(0))> being dependent, let's figure that. 14.6.2.1 last bullet:

a template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent

so sizeof(f(0)) must be value-dependent. 14.6.2.3p2:

Expressions of the following form are value-dependent if the unary-expression is type-dependent ... sizeof unary-expression

so we're dependent if f(0) considered dependent. (Little experimenting shows gcc treats member any function dependent and free functions not dependent.) 14.6.2.2:

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

And I don't see either type dependent subexpressions or anything relevant in the exception list.

ReLated :

The answer hinges on whether m can be looked up to determine that it is a member of the current instantiation. The id-expression m is transformed to a class member access (*this).m, meaning that the rules for qualified name lookup within a class member access are applicable.

In general, the type of a type-dependent expression cannot be determined. It's not completely clear whether an exception should be made for (*this). and this->. An expression containing this is type-dependent, but both (*this). and this-> unambiguously name the current instantiation.

m

The expression m is indeed not type-dependent, because it refers to a member of the current instantiation.

In the context of a non-static member, m is transformed into the class member access expression (*this).m.

[class.mfct.non-static]/3

When an id-expression (5.1) that is not part of a class member access syntax (5.2.5) and not used to form a pointer to member (5.3.1) is used in a member of class X in a context where this can be used (5.1.1), if name lookup (3.4) resolves the name in the id-expression to a non-static non-type member of some class C, and if either the id-expression is potentially evaluated or C is X or a base class of X, the id-expression is transformed into a class member access expression (5.2.5) using (*this)

The transformation occurs because m is a member of class A used within a non-static-member of class A.

[expr.prim.general]/3

If a declaration declares a member function or member function template of a class X, the expressionthis` is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifer-seq and the end of the function-definition, member-declarator, or declarator. It shall not appear before the optional cv-qualifier-seq and it shall not appear within the declaration of a static member function (although its type and value category are defined within a static member function as they are within a non-static member function).

[expr.prim.general]/5

The expression this shall not appear in any other context. [ Example:

class Outer {
    int a[sizeof(*this)]; // error: not inside a member function
    unsigned int sz = sizeof(*this); // OK: in brace-or-equal-initializer

    void f() {
        int b[sizeof(*this)]; // OK

        struct Inner {
            int c[sizeof(*this)]; // error: not inside a member function of Inner
        };
    }
};

—end example ]

The above example explicitly permits use of this within a sizeof expression within a non-static member.

[temp.dep.expr]/2

this is type-dependent if the class type of the enclosing member function is dependent

Therefore this is type-dependent within the definition of a member function of a class template.

[temp.dep.expr]/1

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

However, the above is overruled by the exception in [temp.dep.expr]/5 quoted in the question.

this->m

The expression this->m is also not type-dependent, because it is also a class member access expression which refers to a member of the current instantiation.

std::declval<A>().m

The expression std::declval<A>().m has to be type-dependent, as the return type of std::declval<A>() could depend on the type of A.

[temp.local]/1

Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injectedclass- name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-typespecifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>

Therefore A is transformed to A<T>.

[temp.dep.type]/8

A type is dependent if it is

  • a template parameter,

  • a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent

This confirms that A<T> is a dependent type, meaning that A is also dependent.

[temp.dep.expr]/3

An id-expression is type-dependent if it contains

  • a template-id that is dependent,

So std::declval<A> is a type-dependent expression. It follows that std::declval<A>().m is type-dependent because it contains the type-dependent subexpression std::declval<A>.

&A::m

The expression &A::m logically has to be type-dependent because it has the type int A<T>::* which is a dependent type.

The expression &A::m is transformed to &A<T>::m because A is the injected class name - as shown above.

The id-expression A<T>::m is type-dependent according to [temp.dep.expr]/3 because it contains a template-id A<T> that is dependent. Therefore the expression &A<T>::m is type-dependent according to [temp.dep.expr]/1.

A::m

The expression A::m is transformed to A<T>::m because A is the injected class name - as shown above. The expression A<T>::m is further transformed to (*this).A<T>::m because A<T>::m names a non-static member of A.

The id-expression A<T>::m is type-dependent according to [temp.dep.expr]/3 because it contains a template-id A<T> that is dependent. The class member access expression (*this).A<T>::m refers to a member of the current instantiation, so [temp.dep.expr]/5 applies but does not make the expression type-dependent - nor does it contradict [temp.dep.expr]/3.

Defect?

Given the interpretation above, an id-expression naming a member of A qualified with A or A<T> would become type-dependent, which seems unnecessary and inconsistent. Consider that a type-name qualified with A or A<T> would not be dependent in the same context.

If the intention of [temp.dep.expr]/5 is that (*this).m is not type-dependent, then it follows that (*this).A<T>::m should also not be type-dependent. On the other hand, the intention could be that the name of a non-static member is always dependent. I've posted a question to std-discussion to clarify this point: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/gEvZ7mmXEC8

Static member functions don't have this pointer and static data member is class-specific rather than object-specific. So, static member functions can access static member variables.

This is just your normal qualified lookup. From [basic.lookup.qual]:

The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration.

Then from [class.qual]:

If the nested-name-specifier of a qualified-id nominates a class, the name specified after the nested-namespecifier is looked up in the scope of the class (10.2), except for the cases listed below. The name shall represent one or more members of that class or of one of its base classes (Clause 10). [ Note: A class member can be referred to using a qualified-id at any point in its potential scope (3.3.7). —end note ] The exceptions to the name lookup rule above are the following:

  • a destructor name [...]
  • a conversion-type-id of a conversion-function-id [...]
  • the names in a template-argument of a template-id [...]
  • the lookup for a name specified in a using-declaration [...]

The nested-name-specifier in your example is A, which is a class. None of those exceptions apply. So we just look up the name, Int, in the scope of class.

From [dcl.typedef]:

A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in the way described in Clause 8. A typedef-name is thus a synonym for another type.
[...]
A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier.

So your alias-declaration introduces the name Int into the scope of A, which is found according to the qualified lookup rules I just enumerated.

According to the standard § 14.2/4 Names of template specializations [temp.names]

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.

Edit:

Also, according the standard § 14.6.2.2/2 Type-dependent expressions [temp.dep.expr]:

this is type-dependent if the class type of the enclosing member function is dependent (14.6.2.1).

Thus, in order to call bar.baz<int>() via this you need to prefixed by the keyword template:

this->bar.template baz<int>();

LIVE DEMO

[Reason:] The compiler needs this "redantant" use of template keyword, because it can't decide whether the token < is operator< or the beginning of a template argument list.

Comments


Message :
Login to Add Your Comments .
How to disable registered OpenCL platforms on Windows?
Is Observable broken in Angular 2 Beta 3?
Cross-thread operation not valid when using Invoke
How to pass an IEnumerable or queryable list of properties from Controller to View
Finding numbers after a certain keyword using Python
Pocketsphinx recognizes random phrases in a silence
Passing non-thread-safe objects through thread-safe containers
React scroll nav
BizTalk WCF-BasicHttp Adapter does not allow Empty string for Service Certificate Props
Why property ''cause" of Exception is repeating forever?
Privacy Policy 2017 © codingdir.com All Rights Reserved .