Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function template overloading with variadic templates: Intel c++ compiler version 18 produces different result from other compilers. Is intel wrong?

Consider the following code snippet:

template<typename T, template<typename, typename ...> class A, typename ... Ts>
int a(A<T, Ts...> arg){
  return 1; // Overload #1
}

template<typename A>
int a(A arg) {
  return 2;  // Overload #2
}

template<typename T>
struct S{};

int main() {
  return a(S<int>());
}

Upon calling function a with an instance of a template class, I expect the compiler to select the more special function overload #1. According to the compiler explorer, clang, gcc and intel up to version 17 actually do select overload #1. In contrast, later intel compiler versions (18 and 19) select overload #2.

Is the code ill-defined or are the more recent intel compiler versions wrong?

like image 408
user2296653 Avatar asked May 02 '19 10:05

user2296653


1 Answers

The following fails to call a() on icc 19.01:

template<template<typename, typename ...> class A, typename T, typename ... Ts>
int a(A<T, Ts...> arg){
    return 1;
}

template<typename T>
struct S{};

int foo()
{
    return a(S<int>());
}

It simply can't consider that a() as a candidate, and that's why the overloading is different in the question.

C++17 draft says:

(where P is the template-template parameter, and A is the instantiating argument)

17.3.3 Template template arguments

  1. A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A. If P contains a parameter pack, then A also matches P if each of A’s template parameters matches the corresponding template parameter in the template-head of P.

So far so good, <int argument head matches the parameter head <T.

Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent (17.6.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively.

Still looks good, int and T match.

When P’s template-head contains a template parameter pack (17.6.3), the template parameter pack will match zero or more template parameters or template parameter packs in the template-head of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs).

This is more difficult to parse, but yet it seems OK to me. From what I understand, the compiler should have matched the argument with the template-template parameter. It explicitly talks about zero or more, and we have zero here.

like image 149
Michael Veksler Avatar answered Oct 24 '22 22:10

Michael Veksler