I encountered a problem. When I use something like std::function<A(Fs...)>
it doesn't work, but std::function<A(Fs..., B)>
does work. This is under Clang 8.0; none of it works under GCC.
Here is the example:
#include <functional>
template<typename A, typename B, typename ...Fs>
void func_tmpl1(std::function<A(Fs..., B)> callable)
{
}
template<typename A, typename ...Fs>
void func_tmpl2(std::function<A(Fs...)> callable)
{
}
class Cls1{};
void func0(std::function<void(float, Cls1)> callable)
{
}
int main()
{
std::function<void(float, Cls1)> f1 = [](float a, Cls1 b){};
func0(f1);
func0([](float a, Cls1 b){});
func_tmpl1<void, Cls1, float>(f1); // fails in GCC
func_tmpl2<void, float, Cls1>(f1);
func_tmpl1<void, Cls1, float>( // fails in GCC
[](float a, Cls1 b)
{
}
);
func_tmpl2<void, float, Cls1>( // fails in both
[](float a, Cls1 b)
{}
);
return 0;
}
On Godbolt, we can see GCC always fails, but Clang only fails at the last function call. Can anyone explain what's happening here?
For convenience, let's call the three failed calls in your code #1, #2 and #3.
The problem is, when template arguments corresponding to a template parameter pack are explicitly specified, does the template parameter pack still participates in template argument deduction, and if it does, does deduction fail makes the whole call ill-formed?
From [temp.arg.explicit]/9:
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.
We can infer that the template argument deduction should still be performed.
In the declaration of func_tmpl1
, std::function<A(Fs..., B)>
is a non-deduced context ([temp.deduct.type]/9: "If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context."), so template argument deduction for Fs
should be ignored and #1 and #2 are both well-formed. There is a GCC bug report.
For #3, template argument deduction obviously fails (std::function<A(Fs...)>
vs a lambda type), but does deduction fail really make the code ill-formed? In my opinion, the standard is unclear about this, and there is a related issue. From the response of CWG, #3 is indeed ill-formed.