检查容器类中是否存在函数和隐式推导规则的C ++概念

时间:2020-05-25 08:35:23

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

我正试图弄清楚如何做一些关于概念和模板类型(例如std :: vector)的棘手的事情。

  1. 我正在尝试应用类似于我在T上使用std :: movable的方式的编译时间约束,但是在具有PushBackMovable的C上。它与函数decl末尾的require一起使用,但是我想保持一致,并将约束放在模板args中。我曾尝试用“ PushBackMovable C”替换“ C类”,但这并没有那么失败,但是更接近我想要的。

  2. 我正在尝试在模板化模板参数中使用模板类型。
    2a。有什么方法可以只声明C并在其中的签名内使用模板args。 功能?例如,我可以删除“ T”和“ Alloc”,然后骑“ _T”和“ _Alloc”吗?它似乎 我无法访问这些参数。我想节省一些代码空间。
    2b。他们是否有办法删除运算符第一个arg上C上的空<>?
    2c。如果我只有PushBackMovable,则编译器可以根据需求推断出C的模板类型, 但随后是clclval 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, " "));
}

谢谢您的帮助。

1 个答案:

答案 0 :(得分:1)

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

此外,请勿将decltypestd::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