首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在requires子句中作为返回类型的概念的常量版本

在requires子句中作为返回类型的概念的常量版本
EN

Stack Overflow用户
提问于 2021-07-27 18:45:50
回答 1查看 173关注 0票数 1

我有一些类A,它有一些const函数和一些非const函数,还有一个合适的概念,比如

代码语言:javascript
复制
class A {
public:
    void modify() {/* ... */}
    void print() const {/* ... */}
}

template<typename T>
concept LikeA = requires (T t, const T const_t) {
    { t.modify() } -> std::same_as<void>;
    { const_t.print() } -> std::same_as<void>;
}
static_assert(LikeA<A>);

我注意到的一件好事是,对于某些函数来说,使用下面的const LikeA auto &a代码实际上是合法的:

代码语言:javascript
复制
void use (const LikeA auto &a) {
    a.print(); // fine, print is a const method
    // a.modify(); // illegal, a is a const reference [at least for use(A a) itself, but this is not my point here]
}

static_assert(!LikeA<const A>);

int main() {
    A a1;
    use(a1); //clear, as LikeA<A> holds
    const A a2;
    use(a2); //not obvious, as LikeA<const A> does not hold
}

我研究了cppreference上的定义,我无法真正解释这种行为,我希望它是非法的,尽管直觉上,这正是我想要的。

现在来看一下我的实际情况:我有一个holder类AHolder,它返回const A&作为它的方法之一,并且我希望这个holder类有一个合适的概念,它也适用于任何其他持有满足LikeA的东西的持有者,所以我尝试了:

代码语言:javascript
复制
class AHolder {
public:
    const A& getA() {return _a;}
private:
    const A _a;
};

template<typename T>
concept LikeAHolder = requires (T t) {
    {t.getA() } -> LikeA;
};

static_assert(LikeAHolder<AHolder>); //fails

这是失败的,因为const A&根本不满足LikeA,所以我想将其调整为

代码语言:javascript
复制
template<typename T>
concept LikeAHolder = requires (T t) {
    {t.getA() } -> const LikeA; //invalid syntax
};

static_assert(LikeAHolder<AHolder>);

本着与use方法类似的示例精神,也接受了const A

是否有这样的语法要求返回类型的t.getA满足LikeA,同时考虑返回类型将是const

此外,如何在use(const LikeA auto &a)方法中检查概念,使其行为类似于解释?

(我的第一个问题对我来说更重要)

我考虑过的一些可能的解决办法:

  • 返回一个非const引用。这将使上述代码成为非法,但当然会严重破坏const-correctness,因为_a也必须是非const的,用户只需更改AHolder的私有属性即可。
  • 有两个概念LikeALikeConstA。然后返回类型可以是LikeConstA,只需要const方法。这应该是可行的,但感觉非常笨拙,而不是如何使用概念,这也引入了更多的概念,对于最终用户来说是必要的,而最终用户不得不去操心这些概念,等等。在概念

LikeA中,检查模板类型T是否是常量(通过std::is_const),如果是的话,不需要非const-methods。这在上面的例子中是可行的,但是产生了我们现在只需要的不想要的效果。

代码语言:javascript
复制
class B {
public:
    void print() const {/* ... */}
}

static_assert(LikeA<const B>);

(当然,对于一个已经改编过的LikeA来说),这也是错误的。

  • LikeA的定义中,使用std::remove_referencestd::const_cast来丢弃引用/一致性,然后检查所需的函数。首先,我不知道这是否总是适用于更复杂的类型,但即使如此,这也产生了

所不希望的效果。

代码语言:javascript
复制
static_assert(LikeA<const A>);

将是真实的,打破(或至少弯曲)的语义的概念。

为了总结并确保你不会误解我的意思,我想有个办法

const-correctness

  • does不使用第二个“为最终用户”的概念,
  • 确实强制执行。我的意思是,定义辅助概念或使用一些有助于定义上述概念的标准库当然是可以的,但使用ALikeA等并不需要任何实际要求。
  • 并不简单地忽略const类型的非const要求(正如我前面提到的,这将是编译方面的好,但在语义上是错误的)
  • 并没有将LikeA<const A>定义为真正的

理想情况下,只有一个功能可以像前面提到的那样工作。

代码语言:javascript
复制
template<typename T>
concept LikeAHolder = requires (T t) {
    {t.getA() } -> const LikeA; //invalid syntax
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-27 20:06:53

代码语言:javascript
复制
{[](const LikeA auto&){}( t.getA() )}

注意,一个非const&返回的getA将传递这一信息。

我做了一个lambda做了一个概念检查,然后确保t.getA()通过它。

代码语言:javascript
复制
void use (const LikeA auto &a)

这是缩写

代码语言:javascript
复制
template<LikeA A>
void use (const A&a)

当使用T const调用时,它将推导出A=T而不是A=T const。为什么?因为它抽象地“更正确”。具体来说,有一堆关于模板参数类型演绎如何工作的规则。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68550283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档