【问题标题】:C++ function template argument deductionC++ 函数模板参数推导
【发布时间】:2021-08-31 14:21:11
【问题描述】:

我有一个智能指针的类模板,我想要一个 operator+()

template<typename T, typename U>
class Foo{};

template<typename T, typename U>
std::unique_ptr<Foo<T,U>> operator+(std::shared_ptr<const Foo<T, U>>, std::shared_ptr<const Foo<T, U>>);

我现在希望以下内容与 tempate 参数推导一起使用:

std::shared_ptr<Foo<T, U>> a, b, c;

auto d = a + b + c;

当然不是,因为ab 是指向非const 的指针,而不是指向const 的指针。它也不起作用,因为a + b 是唯一指针而不是共享指针。

是否有一个优雅的解决方案可以使这种推论发挥作用?使用运算符,我真的不想明确指定模板参数。我看到的唯一可行的方法是对shared_ptrunique_ptr 以及const 和非常量的所有排列重载operator+,但要编写16 个函数定义。

【问题讨论】:

  • 你为什么要那个,而不是*d = *a + *b + *c?也就是为什么要这些类型的语义与其他指针类型的语义不一致?
  • 这听起来像是一个 XY 问题。将两个指针相加是什么意思?那有什么作用?很可能这不是一个简单的添加,您应该使用命名函数,然后它会给您auto d = named_function(c, named_function(a, b)。也就是说,我宁愿有一个函数通过引用获取底层对象 (Foo&lt;T, U&gt;),那么你不必担心 const 与否,你可以像 auto d = named_function(*c, named_function(*a, *b) 一样调用它
  • 这两个 cmets 的答案是,我一直在努力在 Foo 几乎总是以指向 const 的共享指针的形式存在的上下文中寻求一个干净方便的接口。取消引用 sum 中的每个参数或链接命名函数在我看来根本不那么干净。然而,我理解,如果添加两个指针与添加两个值具有完全相同的语义,它确实可能会导致更多的混乱而不是方便,所以我可能会选择一个采用 const refs 的函数。
  • 如果您通常使用指向 const 的共享指针,并且如果创建新对象时没有大张旗鼓(例如在计算算术表达式时),那么您可能正在尝试实现 flyweight或某种copy on write 对象。这不是您应该尝试使用运算符重载技巧的那种事情。

标签: c++ template-argument-deduction


【解决方案1】:

实现一个模板,获取对Foo 的 const 引用,然后使用使用此实现的任意参数创建另一个模板。

以下创建始终返回包含默认初始化Foounique_ptr

template<typename T, typename U>
class Foo{};

template<typename T, typename U>
std::unique_ptr<Foo<T,U>> add_foos(const Foo<T, U>& f1, const Foo<T, U>& f2)
{
    return std::make_unique<Foo<T, U>>();
}

template<typename T, typename U>
auto operator+(T t, U u)
{
    // use the function above here
    return add_foos(*t, *u);
}

编辑:

使用来自 cmets 的 @NathanOlivers 建议:最好不要将此应用于与 Foo 无关的操作数

【讨论】:

  • 这确实有效并且看起来很干净,但是为什么您的operator+ 和基本上任何其他也适合该签名的非模板operator+ 都没有歧义?
猜你喜欢
  • 1970-01-01
  • 2021-06-16
  • 1970-01-01
  • 2018-12-05
  • 2013-03-14
  • 1970-01-01
  • 2014-04-17
  • 1970-01-01
  • 2020-07-09
相关资源
最近更新 更多