模板参数推导由于恒定性不一致而失败

Template argument deduction failure due to inconsistent constness

本文关键字:恒定性 不一致 失败 参数      更新时间:2023-10-16

考虑以下内容(它不能编译,但我们稍后会修复它(:

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);
}

模板函数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*’

很明显,类型推导规则还不够宽松,不允许在同时遵守const T*T*的情况下推导出const T*。好的,好的。这很容易用石膏修复:

bar(foo, static_cast<const int *>(&n));

但这很丑陋。C++17 有std::as_const(),这使得它不那么丑陋(&std::as_const(n)(,但在我目前的项目中,我仅限于 C++14,悲伤的脸。

:有没有办法重新排列此代码,以便在不显式指定bar()模板参数和不强制转换以解决不明确的恒常性的情况下成功进行类型推断?允许跳出框框思考,只要我可以将函数指针及其参数传递给模板函数!

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

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);
}

但是在这一点上,我想知道为什么函数指针需要分解。为什么不接受任何可赎回的?

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);
}

另外,请记住,C++17 优惠std::invoke

std::invoke(foo, &n);