繁体   English   中英

您如何在 C++ 概念中定义 emplace_back 和其他可变参数模板函数?

[英]How do you define emplace_back and other variadic template functions in a C++ concept?

我正在尝试为允许 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) };
}

我的问题是如何使用可变参数模板参数定义 emplace_back ? 我正在使用 Visual Studio 2019,但如果它不受支持,我会对正确的语法感兴趣。

可能最值得做的就是a.emplace_back(); .

您的push_back要求也没有正确的语法。 我想你想要:

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();
};

需求不检查函数签名; 他们检查表达式的有效性(无需实例化更多模板)。 如果我们有一个类:

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&&...);
};

然后忽略SequenceContainer要求, PushBackContainer<StrangeContainer>将是 true,并且它也将满足与push_back相关的标准自己的要求。 它满足技术要求,即使它有一些令人惊讶的效果,例如push_back("")

所以对于push_back ,我们实际上只是检查它是否可以使用const左值和非const右值调用。 (标准实际上还要求可以使用非const左值和const右值调用它,这些情况与使用const左值调用时具有相同的行为。)

(如果你真的想测试一个确切的push_back签名,你可以尝试static_cast<void (ContainerType::*)(typename ContainerType::value_type&&)>(&ContainerType::push_back); - 但不推荐这样做,因为成员函数命名空间std中的签名不需要与所描述的完全相同,只需可以使用与所描述的声明相同的参数调用。)

此外,标准容器类模板对其push_backemplace_back函数没有任何限制。 具有push_back的模板的每个实例都声明了两个重载,无论类型是否可复制和/或可移动。 如果没有,实际调用或以其他方式使用push_back函数将是一个错误,但它“存在”是为了需要表达式和 SFINAE 上下文。 同样, emplace_back成员模板被声明为接受任意数量的具有任何类型和值类别的参数,无论它们是否可以用作value_type构造函数参数。

因此,我们想要测试以找出容器是否有一个带有本质上普通可变参数函数声明的emplace_back需要表述为: 可以使用任意数量的参数调用emplace_back ,每个参数都有任何可能的类型,每个参数都可以是左值还是右值? 我认为没有任何方法可以在 C++ 中真正回答这个问题,使用需要表达式、SFINAE 技巧或其他方式。 因此,我只会对某种emplace_back存在进行一个简单的测试,而该测试也可能尽可能简单:零参数。

您可以变得更emplace_back ,还可以测试一些其他情况: emplace_back是否接受不同数量的参数,最多达到某个固定的最大值? 它接受左值和右值参数吗? 它是否接受虚拟struct类型的参数? 不是 MoveConstructible 的虚拟struct类型? constvolatileconst volatile类型? 以上所有可能的组合? 但是,由于您永远不会涵盖所有情况,与添加检查所需的工作量、复杂性和维护相比,像这样的每个部分增强真正提供了多少价值?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM