为什么有时模板参数解压缩不适用于std :: function?

问题描述 投票:4回答:1

我遇到了一个问题。当我使用类似std::function<A(Fs...)>的命令时不起作用,但是std::function<A(Fs..., B)>在clang8.0下仍然有效。他们都不在gcc下工作。这是示例:

#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); //fail in gcc
    func_tmpl2<void, float, Cls1>(f1);

    func_tmpl1<void, Cls1, float>( //fail in gcc
        [](float a, Cls1 b)
        {

        }
    );
    func_tmpl2<void, float, Cls1>( //fail in both
        [](float a, Cls1 b)
        {}
    );

    return 0;
}

godbolt中,我们可以看到gcc总是失败,但是clang仅在上次函数调用时失败。谁能解释这里发生了什么?

c++ templates c++17 variadic-templates std-function
1个回答
0
投票

为方便起见,让我们在代码#1,#2和#3中调用三个失败的电话。

问题是,当显式指定与模板参数包相对应的模板参数时,模板参数包是否仍参与模板参数推导,如果这样做,推导是否失败会使整个调用格式错误?

来自[temp.arg.explicit]/9

模板参数推导可以扩展模板的顺序与模板参数包相对应的参数,即使序列包含显式指定的模板参数。

我们可以推断出仍应执行模板参数推导。

func_tmpl1的声明中,std::function<A(Fs..., B)>是一个非推论上下文([temp.deduct.type]/9:“如果P的模板参数列表包含的包扩展不是最后一个模板参数,则整个模板参数列表为非推论上下文。”),因此应忽略Fs的模板参数推论,并且#1和#2的格式都正确。有一个GCC bug

对于#3,模板参数推导显然会失败(std::function<A(Fs...)>与lambda类型),但是推导失败真的会使代码格式错误吗?在我看来,标准对此尚不明确,并且存在related issue。从CWG的响应来看,#3确实是不正确的。

© www.soinside.com 2019 - 2024. All rights reserved.