Template arguments deduction for function parameter pack followed by other parameters

眉间皱痕 提交于 2019-12-12 10:39:02

问题


Is the deduction for f1 and f2 ill-formed?

template<class... T, class U>
void f1(T..., U){}

template<class... T>
void f2(T..., int){}

int main()
{
    f1(1);
    f2(1);
    return 0;
}

g++ accepts both, clang only accepts f2, and msvc rejects both.

Related standard wording:

[temp.deduct.call]

When a function parameter pack appears in a non-deduced context ([temp.deduct.type]), the type of that parameter pack is never deduced.

[temp.deduct.type]p5

The non-deduced contexts are:

  • A function parameter pack that does not occur at the end of the parameter-declaration-list.

So it seems that MSVC is correct in rejecting both?

Does it mean that any instantiation of the templates will be ill-formed, even if you specify the template args explicitly?

f1<int>(1, 2); // ill-formed?
f2<int>(1, 2); // ill-formed?

If that's the case, why allow such declarations at first place?


回答1:


There's a DR for this specific issue DR1388. Aparently, it seems that GCC and CLANG haven't implemented it yet CLANG DR1388.

Does it mean that any instantiation of the templates will be ill-formed, even if you specify the template args explicitly?

f1<int>(1, 2); // ill-formed?
f2<int>(1, 2); // ill-formed?

If that's the case, why allow such declarations at first place?

No if you specify explicitly the template arguments, no deduction occurs and as such the code showed above is legal.




回答2:


I've looked into this exact question myself and I've found it surprisingly difficult to get a clear answer. As best I can tell, f1(1) should be rejected but f2(1) should be accepted.

That said:

  • clang++-5.0 accepts both
  • g++-6 accepts both
  • EDG 4.14 rejects both

As you pointed out, a function parameter pack that does not occur at the end of the list is a non-deduced context ([temp.deduct.type] p5):

The non-deduced contexts are:

  • ...
  • A function parameter pack that does not occur at the end of the parameter-declaration-list.

and [temp.deduct.call] p1 (amended via CWG 1388) clarifies that such a parameter pack is never deduced.

When a function parameter pack appears in a non-deduced context, the type of that parameter pack is never deduced.

Additionally, [temp.arg.explicit] p3 specifies:

A trailing template parameter pack (14.5.3) not otherwise deduced will be deduced to an empty sequence of template arguments.

so, taking this into account for the f2(1) call: the pack T is a trailing template parameter pack (although it is not a trailing function parameter pack), so it deduced to an empty pack and the call is valid.

However, for f1(1), the pack T is also not a trailing template parameter pack because it is followed by U, so it is not assumed to be an empty pack per [temp.arg.explicit] p3. Therefore, since the template paramter pack T cannot be deduced for the call to f1(1), it should not take part in overload resolution and the call should fail.


Note that several similar questions/examples have been brought up in other discussions, but that they are all subtly different:

  • The f(0) call in the example code of CWG 1388 and CWG 1399 is valid because the pack in question is a trailing template parameter pack, so it falls into the case I mentioned above. Here is the code from CWG 1399:
    template <class... T>
    void f(T..., int, T...) { }
    
    int main() {
      f(0);          // OK
      f<int>(0,0,0); // OK
      f(0,0,0);      // error
    }
    
  • The example code in the discussion of LLVM bug 21774 is similar to the CWG 1399 example, the pack is a trailing template parameter pack. Likewise for this question.
  • CWG 2055, which is unresolved, touches upon a similar test case. Whenever that gets resolved, its resolution will likely shed some light as to the proper behavior of the examples in this question. Here is the issue mentioned in CWG 2055:

    It is not clear that [the current wording of the standard] permits an example like:

    template<typename... T> void f(typename T::type...)   {
    }
    
    int main() {
      f<>();
    }
    


来源:https://stackoverflow.com/questions/36640883/template-arguments-deduction-for-function-parameter-pack-followed-by-other-param

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!