c++ - 由于常量不一致导致模板参数推导失败

标签 c++ c++14 constants template-argument-deduction

考虑以下问题(其中 doesn't compile ,但我们稍后会解决这个问题):

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*’

很明显,type deduction rules不够宽松,无法在同时观察到 const T*T* 时推导 const T*。好的。这很容易fix with a cast :

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

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

Q:有没有一种方法可以重新排列此代码,以便类型推导成功,而无需显式指定 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);

关于c++ - 由于常量不一致导致模板参数推导失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56581992/

相关文章:

c++ - boost multi_index 示例 : error: invalid operands to binary expression

c++ - 从图中删除边

c++ - 考虑到模板参数改变 if 语句条件

c++ - gcc vs clang - 使用 `make_overload` 可变 lambda 继承时的模糊重载

c++ - 谁能解释一下这个 C++ 程序。结果很奇怪 :(

c++ - 为什么一个方法会对同一个变量有 const 和非 const 参数?

c++ - GCC7 在同一个类中推断出存在 const 修饰符

c++ - 创建动态pthread_t时出错

c++ - 如何通过 std::call_once 使用重载函数

ruby-on-rails - 将哈希常量克隆到新变量中,而不会在使用 .each block 更新时改变常量?