[英]How do you define emplace_back and other variadic template functions in a C++ concept?
I'm trying to define a C++ concept for standard library containers that allow push_back/emplace_back:我正在尝试为允许 push_back/emplace_back 的标准库容器定义 C++ 概念:
template <class ContainerType>
concept PushBackContainer = requires(ContainerType a)
{
requires SequenceContainer<ContainerType>;
{ a.push_back(typename ContainerType::const_reference& v) };
{ a.push_back(typename ContainerType::value_type&& v) };
// How do you define a variable templated function:
{ template< class... Args > a.emplace_back(Args&&... args) };
}
The problem I have is how do I define emplace_back with its variadic template arguments?我的问题是如何使用可变参数模板参数定义 emplace_back ? I'm using Visual Studio 2019 but if this isn't supported I'd be interested in the correct syntax come the time it is.
我正在使用 Visual Studio 2019,但如果它不受支持,我会对正确的语法感兴趣。
Probably about the best that's worth doing is just a.emplace_back();
可能最值得做的就是
a.emplace_back();
. .
Your push_back
requirements don't have a correct syntax, either.您的
push_back
要求也没有正确的语法。 I think you want:我想你想要:
template <class ContainerType>
concept PushBackContainer = requires(
ContainerType& a,
typename ContainerType::value_type const& cv,
typename ContainerType::value_type& v)
{
requires SequenceContainer<ContainerType>;
a.push_back(cv);
a.push_back(std::move(v));
a.emplace_back();
};
Requirements don't check for a function signature;需求不检查函数签名; they check for the validity of an expression (without instantiating more templates than necessary).
他们检查表达式的有效性(无需实例化更多模板)。 If we had a class like:
如果我们有一个类:
class StrangeContainer {
public:
using value_type = std::string;
using const_reference = const value_type&;
private:
struct ValueHolder {
ValueHolder(const std::string& s) : value(s) {}
ValueHolder(std::string&& s) : value(std::move(s)) {}
std::string value;
};
public:
void push_back(ValueHolder);
template <typename ... Args>
void emplace_back(Args&&...);
};
then ignoring SequenceContainer
requirements, PushBackContainer<StrangeContainer>
would be true, and it would also satisfy the Standard's own requirements related to push_back
.然后忽略
SequenceContainer
要求, PushBackContainer<StrangeContainer>
将是 true,并且它也将满足与push_back
相关的标准自己的要求。 It satisfies the technical requirements, even though it has some surprising effects like the fact that push_back("")
is ill-formed.它满足技术要求,即使它有一些令人惊讶的效果,例如
push_back("")
。
So for push_back
, we're really just checking that it can be called with a const
lvalue and with a non- const
rvalue.所以对于
push_back
,我们实际上只是检查它是否可以使用const
左值和非const
右值调用。 (The Standard actually also requires that it can be called with a non- const
lvalue and with a const
rvalue, and these cases have the same behavior as when called with a const
lvalue.) (标准实际上还要求可以使用非
const
左值和const
右值调用它,这些情况与使用const
左值调用时具有相同的行为。)
(If you really wanted to test for an exact push_back
signature, you could try static_cast<void (ContainerType::*)(typename ContainerType::value_type&&)>(&ContainerType::push_back);
- but this is not recommended, since member functions in namespace std
are not required to have signatures exactly as described, only to be callable with the same arguments as if declared as described.) (如果你真的想测试一个确切的
push_back
签名,你可以尝试static_cast<void (ContainerType::*)(typename ContainerType::value_type&&)>(&ContainerType::push_back);
- 但不推荐这样做,因为成员函数命名空间std
中的签名不需要与所描述的完全相同,只需可以使用与所描述的声明相同的参数调用。)
Also, the standard container class templates don't have any constraints on their push_back
or emplace_back
functions.此外,标准容器类模板对其
push_back
或emplace_back
函数没有任何限制。 Every instantiation of the templates which have push_back
declares both overloads, whether or not the type is copyable and/or movable.具有
push_back
的模板的每个实例都声明了两个重载,无论类型是否可复制和/或可移动。 If not, it would be an error to actually call or otherwise odr-use the push_back
function, but it "exists" for purposes of requires-expressions and SFINAE contexts.如果没有,实际调用或以其他方式使用
push_back
函数将是一个错误,但它“存在”是为了需要表达式和 SFINAE 上下文。 Likewise, the emplace_back
member template is declared to accept any number of arguments with any types and value categories, no matter whether they can be used as value_type
constructor arguments or not.同样,
emplace_back
成员模板被声明为接受任意数量的具有任何类型和值类别的参数,无论它们是否可以用作value_type
构造函数参数。
So what we would want to test to find out if the container has an emplace_back
with an essentially ordinary variadic function declaration would need to be phrased as: Can emplace_back
be called with any number of arguments, with each having any possible type and each being either an lvalue or rvalue?因此,我们想要测试以找出容器是否有一个带有本质上普通可变参数函数声明的
emplace_back
需要表述为: 可以使用任意数量的参数调用emplace_back
,每个参数都有任何可能的类型,每个参数都可以是左值还是右值? I don't think there's any way to really answer that within C++, using requires-expressions, SFINAE tricks, or otherwise.我认为没有任何方法可以在 C++ 中真正回答这个问题,使用需要表达式、SFINAE 技巧或其他方式。 So I would just do one simple test for existence of some sort of
emplace_back
, and that test might as well be as simple as possible: zero arguments.因此,我只会对某种
emplace_back
存在进行一个简单的测试,而该测试也可能尽可能简单:零参数。
You could get fancier and also test for some additional cases: Does emplace_back
accept different numbers of arguments, up to some fixed maximum?您可以变得更
emplace_back
,还可以测试一些其他情况: emplace_back
是否接受不同数量的参数,最多达到某个固定的最大值? Does it accept lvalue and rvalue arguments?它接受左值和右值参数吗? Does it accept arguments of dummy
struct
types?它是否接受虚拟
struct
类型的参数? Dummy struct
types that aren't MoveConstructible?不是 MoveConstructible 的虚拟
struct
类型? const
, volatile
, and const volatile
types? const
、 volatile
和const volatile
类型? All possible combinations of all of the above?以上所有可能的组合? But since you'll never cover all the cases, how much value does each partial enhancement like this really give, compared to the effort, complexity, and maintenance needed to add checks?
但是,由于您永远不会涵盖所有情况,与添加检查所需的工作量、复杂性和维护相比,像这样的每个部分增强真正提供了多少价值?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.