为什么这个函数指针的可变模板参数推导失败

Why does the variadic template argument deduction fail for this function pointer?

本文关键字:参数 失败 函数 指针 为什么      更新时间:2023-10-16

在下面的最小示例中,S::foo工作,但S::bar失败。

唯一的区别是参数包TsUs的顺序。

struct FPtrS::lol是我找到的最好的变通方法,但在实践中使用起来相当不舒服。

为什么bar的参数推导失败(尤其是因为我已经明确指定了类型,所以根本不应该进行推导)?这是编译器错误(出现在clang++ 3.5g++ 4.9中),还是出于某种原因在标准中?

template<typename ... Ts>
struct FPtr {
    FPtr(void (*val)(Ts ...)) : val{val} {}
    void (*val)(Ts ...);
};

template<typename ... Ts>
struct S {
    template<typename ... Us>
    void lol(FPtr<Us ..., Ts ...>) {}
    template<typename ... Us>
    void foo(void (*)(Ts ..., Us ...)) {}
    template<typename ... Us>
    void bar(void (*)(Us ..., Ts ...)) {}
};

void f(int, float) {}
void g(float, int) {}

int main() {
    S<int> s;
    s.lol<float>(FPtr<float, int>(g));
    s.foo<float>(f);
    s.bar<float>(g);
}

错误消息为:

$ clang++ -std=c++14 t27.cpp -Wall -Wextra -pedantic
t27.cpp:31:4: error: no matching member function for call to 'bar'
        s.bar<float>(g);
        ~~^~~~~~~~~~
t27.cpp:18:7: note: candidate template ignored: failed template argument deduction
        void bar(void (*)(Us ..., Ts ...)) {}
             ^

注意:我已经在GCC和LLVM错误跟踪器上报告了这个错误。

我已经用Clang和GCC测试了这段代码,但它们都无法编译程序。我认为这是两个编译器中的一个错误。出现在参数列表末尾之前的函数参数包是非推导上下文。在替换明确指定的模板参数后,它应该构建函数

template<>
S<int>::bar(void (*)(float, int));

其应当与呼叫相匹配。Clang和GCC以前在这样的领域遇到过问题,众所周知,他们的诊断没有多大帮助。然而,令人惊讶的是,VC++编译了代码。

考虑以下两种编译器都可以使用的内容。

template<class... Ts>
struct S {
    template<class... Us>
    void bar(Us..., Ts...);
};
int main() {
    S<int>().bar<int>(1, 2);
}

您的程序具有相同的语义,应该一视同仁。