std::function::target with template parameter pack gives "error: expected primary-expression"

std::function::target with template parameter pack gives "error: expected primary-expression"

当我尝试使用模板参数包在 std::function 对象上调用方法 target 时,编译器会抛出错误,但如果在代理变量。

示例,修改自cppreference.com

#include <functional>
#include <iostream>

int f(int, int) { return 1; }
int g(int, int) { return 2; }

template <typename... Args>
void test(std::function<int(Args...)> const& arg)
{
    auto && ptr = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'

    if (ptr && *ptr == f)
        std::cout << "it is the function f\n";
    if (ptr && *ptr == g)
        std::cout << "it is the function g\n";
}

int test()
{
    test<int, int>(std::function<int(int, int)>(f));
    test<int, int>(std::function<int(int, int)>(g));
}

我尝试了各种其他方式来调用 target,包括以下方式:

int (*const* ptr)(Args...) = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
int (*const* ptr)(int, int) = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
int (*const* ptr)(int, int) = arg.target<int(*)(int, int)>(); // error: expected primary-expression before 'int'

const std::function<int(Args...)>& func = arg;
auto && ptr = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'

编译器似乎只在使用代理变量时才满足,如下所示:

const std::function<int(int, int)>& func = arg;
auto && ptr = func.target<int(*)(Args...)>(); // OK, but requires specifying the template arguments for func

可以看出,此解决方法与之前的非工作示例不同,仅通过显式指定函数参数而不是依赖参数包。 (我可以用 static_cast 例如 static_cast<std::function<int(int,int)>&>(arg).target<int(*)(Args...)>() 绕过代理变量,但这也需要知道转换的参数。)如果我已经知道将要使用什么参数,那么我就不会使用可变参数模板,因为它不是必需的。但既然我没有,我该如何解决这个问题?我做错了什么,这是一个编译器错误,还是这里到底发生了什么?

注:

作为参考,我正在 Windows 10 上使用 GCC 6.3.0 版和 MinGW 进行编译。

arg.template target<int(*)(Args...)>(

当 std 函数类型依赖于模板参数时,您需要消除歧义。

C++ 在调用函数之前解析模板函数时不知道 arg.target 是模板。它必须在调用之前解析它;这不是宏。

因此,无论何时在依赖于模板参数的上下文中命名类型,或在依赖于模板参数的上下文中实例化模板,都必须告诉解析器。