Sample template for dependent names

This issue is based on the C ++ Link section : the dependent name is a template ambiguous element for the dependent name .

I understood when calling the template member function in the template class, the keyword template is necessary so that the compiler knows that the following parentheses are used to indicate the template argument. Similar to the example used in this section.

template<typename T> struct S { template<typename U> void foo(){} }; template<typename T> void bar() { S<T> s; s.foo<T>(); // error: < parsed as less than operator s.template foo<T>(); // OK } 

However, in the subsequent part, it describes when a template name appears in a member access expression (after β†’ or after.), A disambiguator is not needed if there is a template with the same name that was found by a regular search in the context of the expression. .

Then it comes with the following code. Comparing with the previous example, it defines the set function, whose name also exists in the standard library. At the same time , using std :: set is configured to make the template template visible in the template function. In this condition, even if the keyword template is not specified, it still works well.

 #include <set> using std::set; // makes 'set' visible to lookup from bar template<typename T> struct S { template<typename U> void set(){} }; template<typename T> void bar() { S<T> s; s.set<T>(); // not an error if ::set is visible: // (and since C++11, this is well-formed) s.template set<T>(); // works with and without ::set } 

Based on my understanding, I tried my own version

 #include <iostream> template <typename T> struct S{ template <typename U> void func(){ std::cout << "In S::func\n"; } }; // In order to make member template function is visible in function test, // defining a global template function **func** whose name is same with one // member template function in struct S. template <typename M> void func(){ std::cout << "from ordinary func\n"; } template <typename M> void test(){ S<M> s; func<M>(); // test func template function is visible in test function s.func<M>(); } int main(){ test<int>(); } 

The error message is detailed below.

 [17:17:50][ ryu@C ++_test]$ g++ -g typename2.cpp typename2.cpp:61:7: error: use 'template' keyword to treat 'func' as a dependent template name s.func<M>(); ^ template 1 error generated. 

Any advice is welcome on how to make my own code work well without a keyword template.

+7
c ++ c ++ 11 templates
source share
1 answer

Short version

Do not rely on this. Use the template keyword as you expected, do not try to use such an obscure hack to avoid a few keystrokes. Your code should definitely not compile in accordance with the standard, and the example you provided from cppreference.com may soon also be explicitly forbidden (I don’t know) I think it was really in the first place). GCC and Clang give different results for both of these examples. Even if they compile today, they may fail tomorrow in the next version of the compiler.

Long version

As for the example from cppreference.com , first note that Clang 3.6.0 compiles the code, but GCC 5.1.0 rejects both s.set<T>() and s.template set<T>() with invalid use of 'class std::set<T>' error invalid use of 'class std::set<T>' . I don’t think either of the two compilers does the right thing here according to the standard, but intuitively, the GCC error message makes a lot of sense: what will the value of s.set<T>() with set<T> being the class template specialization?

This is the opposite with your code: Clang rejects it (the error message mentioned in the question seems to be actually related to Clang), and GCC compiles it.

Examples are based on paragraph [3.4.5p1] in the standard (highlighted in all citations):

In an access expression to a member of a class (5.2.5), if. or β†’ a token followed by an identifier followed by an identifier <, the identifier must be checked to determine if the list of arguments to the template (14.2) is the beginning or less than the operator. The identifier is first looked up in the object expression class. If the identifier is not found, then it is looked in the context of the entire postfix expression and we will call the template class .

Part of the class template causes your code to abandon Clang (your func is a function template). Function templates were removed from there as the resolution of defect 141 included in C ++ 11. It is worth mentioning the comment in the defect report:

There seems to be no circumstance under which the use of a non-member template function will be correctly formed as an id-expression of the member-expression class.

I think this suggests the intent of this search rule: it must find well-formed constructions; it is not intended to simply make the parser happy about those <> with some temporary coincidence, which will later be replaced by something else with completely different semantics.

Even with the help of the special search rule above, I'm not sure if the standard allows you to omit template in such cases. Paragraph [14.2p4] states:

When then the member template specification appears. or β†’ in a postfix expression or after a nested qualifier name in qualified-id, and the postfix-expression object expression is a type-dependent or nested name qualifier in the identifier with qualification-id to a dependent type, but the name is not a member of the current one (14.6.2.1 ), the name of the member template must be prefixed with the keyword template . Otherwise, it is assumed that the name is without a pattern.

Both set and func member templates in two examples satisfy the conditions there, respectively. As you can see, there is no mention of an exception to this rule.

Or, in other words, if you want set to resolve as the name of a member template, it must be preceded by template . If this is not the case, it can be resolved as an area of ​​the set namespace, but then the set name itself is no longer a name depending on the template parameters ( set<T> is still dependent, but set itself is not). And then we get to [14.6p10], which says:

If the name does not depend on the template parameter (as defined in 14.6.2), the declaration (or set of declarations) for this name should be in scope at the point where the name is displayed in the template definition; the name is associated with the declaration (or declarations) found at that moment, and this obligation does not depend on the announcements that are visible at the time the instance was created.

After binding, it is cut out on the stone, and a later transition to the member template is not allowed, which makes the cppreference.com example incorrect.

In addition, there is an open problem regarding the applicability of the search rule from [3.4.5p1] to such examples - issue 1835 . Quoting notes:

One possibility might be to limit the search for the class expression of an object when the expression of the object is dependent.

The issue is developing status, which means that informal consensus has been reached in the working group. The fact that this consensus remains remains to be seen, but I would say that there is a good chance that something will change. Relying on such code does not seem like a good idea.


The indicated paragraphs remained unchanged from C ++ 11 until the current working draft (N4431).

+3
source share

All Articles