【问题标题】:Template argument deduction failure due to inconsistent constnessconstness 不一致导致模板参数推导失败
【发布时间】:2019-06-13 13:47:53
【问题描述】:

考虑以下问题(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(),这使它不那么难看 (&amp;std::as_const(n)),但在我当前的项目中,我仅限于 C++14,sadface。

问:有没有办法重新排列这段代码,以便类型推断成功,而无需显式指定bar() 的模板参数,也无需强制转换来解决模棱两可的常量?允许跳出框框思考,只要我可以将函数指针及其参数传递给模板函数!

【问题讨论】:

  • 您可以改为定义const int n = 42; bar(foo, &amp;n);。
  • @vahancho 在我的真实用例中,n 是struct 的变量,不能是const。显然,我可以创建一个单独的 const 引用,但问题的关键是要避免那样做。
  • 您需要两个参数包。一个用于推断传入函数的参数,第二个参数包用于转发的参数。在参数无效的情况下,SFINAE 可用于防止不需要的重载解析,而不是编译错误。附言您的“不编译”版本(在问题本身中)实际上可以编译,因为它与编译的版本相同。
  • @SamVarshavchik 谢谢,很好的建议,我已经“修复”(或者更确切地说是破坏了,呵呵)帖子中的初始代码 sn-p。

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


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 2012-12-06
    • 1970-01-01
    相关资源
    最近更新 更多