【问题标题】:Template functor and class template parameter deduction模板函子与类模板参数推导
【发布时间】:2021-02-07 19:21:28
【问题描述】:

我正在尝试实现一个类,它是跨链表的迭代器。我想将它模板化,以便您可以使用仿函数构造它以确定我们何时迭代到最后,但是我无法通过类构造函数模板推导来推断仿函数的类型。

我正在尝试做的简化示例:

#include <utility>

struct A {};
struct B : A {};

template<typename T, typename F>
struct C
{
    A * a_;
    F f_;

    C(A * a, F && f) : a_(a), f_(std::move(f)) {}
    T & operator*() { return static_cast<T &>(*a_); }
};

int main()
{
    B b;
    C<B> foo(&b, [b]() -> bool { return false; }); // error: wrong number of template arguments (1, should be 2)
    return 0;
}

在尝试实例化对象(使用 c++17 编译)时,我总是遇到模板参数错误,奇怪的是,godbolt 也给了我这些神秘的:error: expression list treated as compound expression in initializer [-fpermissive]error: cannot convert 'main()::&lt;lambda()&gt;' to 'int' in initialization 这没有意义,但可能只是第一个错误的后果。

不应该可以从构造函数参数中推导出函子类型F吗?我在这里做错了吗?

【问题讨论】:

  • Quoth cppreference: "类模板参数推导仅在不存在模板参数列表时执行。如果指定了模板参数列表,则不会进行推导。"这意味着您不能指定某些参数并推导出其他参数 - 您必须指定所有参数,或者不指定任何参数并推导出所有参数。
  • @IgorTandetnik 真的吗?我想只要所有推导的类型都在模板参数列表中的指定类型之后那么它应该可以工作吗?
  • 它以这种方式用于函数模板参数推导,但显然不适用于类模板。对于后者,要么全有,要么全无。这在实际操作中很容易看到:std::pair p{1, 2}; 编译,但 std::pair&lt;int&gt; p{1,2}; 不编译。
  • 该死的,谢谢你的链接......是的,它被埋在了那里的笔记里。页面的第一行似乎确实暗示了部分规范的使用:“为了实例化类模板,必须知道每个模板参数,但不是必须指定每个模板参数。”
  • 我想在这种情况下我也可以让第一个模板参数也可推导出来,这很容易

标签: c++ templates c++17 template-meta-programming


【解决方案1】:

要使 CTAD 工作,您不能提供任何模板参数,并且由于无法推断出 T,因此您还需要提供第二个模板参数(即没有 CTAD)。

例子:

auto l = [b]() -> bool { return false; };
C<B,decltype(l)> foo(&b, std::move(l));

您可以添加一个辅助函数模板:

template<typename T, typename F>
auto C_creator(A* a, F&& f) { return C<T,F>(a, std::forward<F>(f)); }

auto foo = C_creator<B>(&b, [b]() -> bool { return false; });

或者将构造函数更改为采用T* 而不是A*,以便可以推断出T

C(T* a, F&& f) : a_(a), f_(std::move(f)) {}

auto foo = C(&b, [b]() -> bool { return false; });

【讨论】:

  • 这里的希望是必须指定所有类型。在上面的 cmets 中,似乎类模板推论是全有或全无
  • @ZoltanDeWitt 是的,因为每个 lambda 都有一个唯一的类型,这就是解决方法。
  • 在这种情况下,我认为修改构造函数更容易,因此它也可以推断出第一种类型。 decltype 有效,但它使实例化站点更加冗长。
  • @ZoltanDeWitt 当然,如果这是一个选项。我也添加了。
  • @ZoltanDeWitt 好的,我改写了一下。
猜你喜欢
  • 2018-12-05
  • 2015-09-19
  • 2020-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多