Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can `template` keyword qualifier cause code to compile successfully, but differently?

Tags:

c++

templates

I'm reading about the template keyword qualifier (https://www.ibm.com/support/knowledgecenter/SSPSQF_9.0.0/com.ibm.xlcpp111.aix.doc/language_ref/keyword_template_qualifier.html, and Where and why do I have to put the "template" and "typename" keywords?), but there's still something that confuses me.

Is it possible to have code like this, that compiles successfully, but results in two different operations?

SomeObjectInstance.template some_function();
SomeObjectInstance.some_function();
like image 945
Nickolai Avatar asked Jan 24 '18 21:01

Nickolai


1 Answers

Yes, you could write something like that, have it be well-formed, and give different results. Basically your own example:

#include <iostream>

struct foo {
    template <int = 0>
    void some_function() { std::cout << "template\n"; }

    void some_function() { std::cout << "non-template\n"; }
};


int main(void) {
    foo f{};

    f.some_function();
    f.template some_function();

    return 0;
}

Will print what you expect. When the compiler sees the first call to some_function, it must check if it can synthesize the template overload. Which it can, since we provided a default argument to the template parameter. Then it does overload resolution with both candidates, and [over.match.best]/1 tells us that

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

  • F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

We have two equally good implicit conversion sequences (empty), and that bullet explicitly says the non-template version is a better candidate given everything else is the same.

But when the template keyword is used, we defer to [temp.names]/5:

A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template or an alias template.

A template-id has this grammar production in paragraph 1:

simple-template-id:
  template-name < template-argument-list >

template-id:
  simple-template-id
  operator-function-id < template-argument-list >
  literal-operator-id < template-argument-list >

The template-argument-list is optional in all of the above. But an astute reader will notice that the angle brackets aren't specified as optional. It seems that we must name the template member function as some_function<>. But fortunately we are doing a function call. Template argument deduction is happening, and it is for this reason that [temp.arg.explicit]/3 can be applied:

... If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted. ...

So we indeed may write f.template some_function();, and it must refer to a template, according to [temp.names]/5. That should have the effect of removing the non-template overload from consideration.

like image 53
StoryTeller - Unslander Monica Avatar answered Oct 20 '22 22:10

StoryTeller - Unslander Monica