使用概念检查类型 T 是否具有字段 F

Ami*_*rsh 3 c++ reflection c++-concepts c++20

以下concept检查类型T是否具有公共字段foo

template<typename T>               
concept has_field_foo = requires { 
    T::foo;                       
};
Run Code Online (Sandbox Code Playgroud)

有没有办法实现一个泛型concept来检查类型T是否有一个公共字段F,类似于(伪代码......字段F不能像这样传递):

template<typename T, typename F>               
concept has_field = requires { 
    T::F;
};
Run Code Online (Sandbox Code Playgroud)

Ami*_*rsh 8

检查提供的参数是否具有字段F可以通过requires对函数本身的约束轻松实现:

// accepts only parameters that have a 'foo' member
void doSomething(auto i) requires requires { i.foo; } { /* */ }
Run Code Online (Sandbox Code Playgroud)

对于为什么(以及何时)C++20 需要,requires requires请参阅: 为什么我们需要需要需要?

上述方法可以完美地与通用案例重载一起使用:

// the unconstrained version
void doSomething(auto i) { /* */ }
Run Code Online (Sandbox Code Playgroud)

将根据提供的参数选择正确的方法。

代码:https : //godbolt.org/z/u35Jo3


为了有一个通用的概念,我们可以插入一个宏来帮助我们:

#define CREATE_HAS_FIELD_CONCEPT(field)     \
    template<typename T>                    \
    concept has_field_##field = requires {  \
        T::field;                           \
    }
Run Code Online (Sandbox Code Playgroud)

我们实际上没有一个通用的概念,但是我们可以使用上面的宏轻松生成所需的概念:

CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
Run Code Online (Sandbox Code Playgroud)

并使用它(而不是具有上述要求的版本):

void doSomething(has_field_foo auto i) { /* */ }
Run Code Online (Sandbox Code Playgroud)

代码:https : //godbolt.org/z/R9​​nQ7Q


实际创建一个概念有一定的价值,因为它可以参与偏序。

使用普通约束我们不会得到偏序,因为原子约束不被认为是等效的,但原子概念是。

因此,基于普通约束的以下代码因歧义而失败:

void print(auto i) requires requires { i.foo; } {
    std::cout << "foo" << std::endl;
}

void print(auto i) requires requires { i.moo; } {
    std::cout << "moo" << std::endl;
}

void print(auto i) requires requires { i.moo && i.foo; } {
    std::cout << "foo and moo" << std::endl;
}

struct HasFoo { int foo; };

struct HasMoo { int moo; };

struct HasFooAndMoo: HasFoo, HasMoo {};

int main() {
    print(HasFoo{});
    print(HasMoo{});
    print(HasFooAndMoo{}); // compilation error: ambiguity
                           // all 3 'print' functions are proper candidates
                           // no partial ordering for constraints, just for concepts!
}
Run Code Online (Sandbox Code Playgroud)

虽然这个可以按需要工作:

CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
CREATE_HAS_FIELD_CONCEPT(moo); // creates the concept: has_field_moo

void print(has_field_foo auto i) {
    std::cout << "foo" << std::endl;
}

void print(has_field_moo auto i) {
    std::cout << "moo" << std::endl;
}

template<class P>
concept has_fields_foo_and_moo
     = has_field_foo<P> && has_field_moo<P>;

void print(has_fields_foo_and_moo auto i) {
    std::cout << "foo and moo" << std::endl;
}

int main() {
    print(HasFoo{});
    print(HasMoo{});
    print(HasFooAndMoo{}); // partial ordering for concepts rocks!
}
Run Code Online (Sandbox Code Playgroud)