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

标签 c++ visual-c++ c++-concepts

我正在尝试为允许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):
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);-但这是不建议的,因为 namespace std中的成员函数不需要具有完全与所描述的签名相同,只能使用相同的参数进行调用,就像按照说明声明。)

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

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

您可能会觉得更奇特,还可以测试其他一些情况:emplace_back是否接受不同数量的参数,最多达到固定的最大值?它接受左值和右值参数吗?它接受伪struct类型的参数吗?虚拟的struct类型不是MoveConstructible吗? constvolatileconst volatile类型?所有上述所有可能的组合?但是,由于您将永远无法涵盖所有​​情况,因此与添加检查所需的工作量,复杂性和维护相比,这样的每个部分增强实际上能带来多少值(value)?

关于c++ - 如何在C++概念中定义emplace_back和其他可变参数模板函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60491342/

相关文章:

c++ - Stroustrup 的 C++ Book Challenge,有人可以帮助我理解这段代码吗?

c++ - 在 C++ 中从十六进制转换为 unsigned int*

visual-c++ - 基本代码布局问题

c++ - 将具有条件要求的概念形式化

c++ - 概念是由看似会产生无效表达式的类型满足的

c++ - 我应该更喜欢通过嵌套的 typedef 还是继承来调用模板元函数?

c++ - 根据另一个数组的顺序对一个数组进行排序

c++ - C++ 中的 nothrow delete 是什么?

c# - 监控最常见的 Web 浏览器 c#/vc++/c

c++ - 成员函数检查 : Implement compilation-time checkings with C++11 features