由于不一致导致模板参数推导失败

Typ*_*eIA 2 c++ const template-argument-deduction c++14

请考虑以下内容(它不会编译,但稍后会修复):

void foo(const int *n) { }

template <typename ...Args>
void bar(void (*func)(Args...), Args... args) { func(args...); }

int main(int argc, char *argv[])
{
    int n = 42;
    bar(foo, &n);
}
Run Code Online (Sandbox Code Playgroud)

模板函数bar()需要一个函数指针来调用,并将参数包传递给它。gcc 7.4.0诊断以下错误:

test.cpp:6:6: note:   template argument deduction/substitution failed:
test.cpp:11:16: note:   inconsistent parameter pack deduction with ‘const int*’ and ‘int*’
Run Code Online (Sandbox Code Playgroud)

很明显,类型推导规则不够宽松,无法const T*同时观察到const T*和被推导T*。好的。这很容易用演员表修复

bar(foo, static_cast<const int *>(&n));
Run Code Online (Sandbox Code Playgroud)

但这是丑陋的。C ++ 17具有std::as_const()使它变得不那么丑陋的(&std::as_const(n))的功能,但是在我当前的项目中,我仅限于C ++ 14的sadface。

:有没有一种方法可以重新排列此代码,以便类型推断成功完成而无需显式指定模板参数,bar()也可以不强制转换以解决歧义常数?只要我可以将函数指针及其参数传递给模板函数,就可以在框外进行思考!

Gui*_*cot 5

您可以将函数指针和参数的推论分开:

void foo(const int *n) {}

template <typename... FArgs, typename... Args>
void bar(void (*func)(FArgs...), Args&&... args) {
    func(std::forward<Args>(args)...);
}

int main(int argc, char *argv[]) {
    int n = 42;
    bar(foo, &n);
}
Run Code Online (Sandbox Code Playgroud)

但是到那时我不知道为什么需要分解函数指针。为什么不接受任何可呼叫电话?

void foo(const int *n) {}

template <typename F, typename... Args>
void bar(F func, Args&&... args) {
    func(std::forward<Args>(args)...);
}

int main(int argc, char *argv[]) {
    int n = 42;
    bar(foo, static_cast<const int *>(&n));
    bar([](int const*){}, &n);
}
Run Code Online (Sandbox Code Playgroud)

另外,请记住,C ++ 17提供了std::invoke

std::invoke(foo, &n);
Run Code Online (Sandbox Code Playgroud)