繁体   English   中英

你怎么能要求一个概念参数是一个引用`&`类型呢?

[英]How can you require that a concept parameter is a reference `&` type?

在下面的概念实现struct String中, operator()方法不通过引用获取值Source ,但仍然满足Consumer概念。 如何防止String成为有效的Consumer ,特别是通过要求Source source是参考&

template <class Type, class Source>
concept Consumer = requires(Type type, Source & source, std::ranges::iterator_t<Source> position) {
    { type.operator()(source, position) } -> std::same_as<Source>;
};

struct String {
    public:
        std::string operator()(const std::string source, std::string::const_iterator position) {
            return "test";
        }
};

int main(const int, const char * []) {
    String consumer{};
    static_assert(Consumer<String, std::string>);
    auto test = std::string("test");
    consumer(test, std::begin(test));
}

首先,没有理由写type.operator()(source, position) 这很奇怪,它只是排除了某些类型的可调用对象而没有任何好处。

requires-expression中的“参数”作为引用类型和值类型之间也没有区别,除非您要在正文中的某处使用decltype(the_parameter) ,而您可能不会这样做,所以可以删除&

最后,对于可调用对象, type不是一个特别有用的名称。 所以让我们开始吧:

template <class F, class Source>
concept Consumer = requires (F f, Source source, std::ranges::iterator_t<Source> it) {
    { f(source, it) } -> std::same_as<Source>;
};

好吧,现在你的实际问题:

如何防止String成为有效的Consumer ,特别是通过要求Source source是参考&

你不能。 概念不检查签名,它们检查表达式的有效性,并且它是复制范围的有效表达式(当然假设它是可复制的)即使这不是您想要发生的事情。 请不要开始检查operator()的类型(这会阻止使用重载的函数对象、模板或任何默认参数)。 所以一种选择是处理它。

另一个是将一些东西传递给f ,复制不是问题。 喜欢... &source 这使您的Consumer实现更加尴尬,因为...指针。

另一个是将 API 更改为不太可能被错误实现的东西。 就像不是传入(source, it) ,而是传入subrange(it, ranges::end(source)) 如果消费者特别需要原始范围,这是有问题的。 如果他们只需要一个范围,这很好用。 或者,而不是迭代器,传递一个不绑定到原始源的索引。 如果消费者只在随机访问范围内操作,这会使复制问题减少(只是费用),但如果消费者需要在较弱的范围内操作,这可能是不可接受的费用。

您不能(合理地)检测是否采用参考参数。 但是您可以检测它是否可以采用右值:

template <class Type, class Source>
concept ConsumerOfRvalue = requires(Type type, Source &&source, std::ranges::iterator_t<Source> position) {
    type(std::move(source), position);
};

如果函数通过&&const&或值(假设Source是可移动的)获取其参数,那么它将满足ConsumerOfRvalue 因此,您可以让您的Consumer要求类型不满足ConsumerOfRvalue

template <class Type, class Source>
concept Consumer = !ConsumerOfRvalue<Type, Source> &&
    requires(Type type, Source & source, std::ranges::iterator_t<Source> position) {
    { type(source, position) } -> std::same_as<Source>;
};

暂无
暂无

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

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