【问题标题】:C++ Concepts for checking if a function exists in a container class and implicit deduction rules用于检查容器类中是否存在函数的 C++ 概念和隐式推导规则
【发布时间】:2020-09-11 20:54:51
【问题描述】:

我试图弄清楚如何做一些对我来说似乎很棘手的关于概念和模板类型的事情,例如 std::vector。

  1. 我正在尝试应用类似于我在 T 上使用 std::movable 的编译时间约束,但在 C 上使用 PushBackMovable。它适用于函数 decl 尾部的需求,但我希望保持一致并将我的约束放在模板 args 中。我尝试用“PushBackMovable C”替换“class C”,但这并没有那么严重地失败,但更接近我想要的。

  2. 我正在尝试使用模板化模板参数中的模板类型。
    2a。有没有办法只声明 C 并在其签名中使用其中的模板 args 功能?例如,我可以删除“T”和“Alloc”,并使用“_T”和“_Alloc”吗?它似乎 我无法访问这些参数。我想节省一些代码空间。
    2b。他们是一种在运算符的第一个参数上删除 C 上的空 的方法吗?
    2c。如果我只有 PushBackMovable,编译器可以根据需要推断出 C 的模板类型, 但随后 declval barfs。他们是否有任何技巧我"缺少隐式确定模板 参数,特别是在“C”实例上?最好只说“C”。

  3. 他们是否比下面的方法更容易检查方法是否存在?

这是我的两种情况的示例代码:

#include <vector>
#include <type_traits>
#include <algorithm>

template<typename T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C >
concept PushBackMovable = std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(std::move(T{}))),void> &&
                          std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(T{})),void>; 

template<std::movable T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C > 
void operator+=( C<>& lhs, T rhs ) requires PushBackMovable<T, Alloc, C>
{
  lhs.push_back( std::forward<T>( rhs ) );
}

int main() {
  std::vector<int> ints;
  int a = 5;

  ints += 1;
  ints += a;

  std::copy(std::begin(ints), std::end(ints), std::ostream_iterator<int>(std::cout, " "));
}

感谢您的帮助。

【问题讨论】:

  • 在std::move(T{}),std::move 没用。
  • 对于T{},您还期望默认的可构造类型...
  • 还有std::forward&lt;T&gt; 和T 不是转发引用,在按值传递(即,已经复制/移动)的东西上有效地变成std::move。
  • @PiotrSkotnicki: 是允许container.operator+=&lt;int&amp;&gt;(i); ;-)

标签: c++ templates template-meta-programming c++20 c++-concepts


【解决方案1】:

通过使用模板模板参数,您已经将函数限制为遵循标准库模式的容器,以及恰好具有两个类型模板参数的类模板。这是一个强约束,在实践中通常是无用的。也就是说,我建议您改为对由类型模板参数表示的具体类型进行操作,并让概念验证您想要强加的任何要求。

此外,不要使用 decltype 和 std::declval 和 std::is_same 来检查表达式的有效性。概念有一个专门的语法来达到这个目的,就是把这个表达式放在大括号里。

一种解决方案,将您要验证的内容合并到一个概念中,如下所示:

#include <concepts>
#include <utility>
#include <type_traits>

template <typename C, typename T>
concept PushBackMovable = requires (C c, T t) {
    { c.push_back(t) } -> std::same_as<void>;
    { c.push_back(std::move(t)) } -> std::same_as<void>;
};

template <typename T, PushBackMovable<std::remove_reference_t<T>> C>
void operator+=(C& lhs, T&& rhs)
{
    lhs.push_back(std::forward<T>(rhs));
}

DEMO

【讨论】:

  • OP 用右值检查两次push_back,而你也用左值检查(可能是 OP 的意图)。
  • @Jarod42 谢谢,我什至没有注意到。我希望OP会根据自己的需要进行调整。
猜你喜欢
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
相关资源
最近更新 更多