用概念检查属性类型

时间:2020-07-08 09:16:23

标签: c++ c++20 c++-concepts

我想检查struct / class的属性是否符合我的概念要求,但是编译器会抱怨。

示例:

struct N
{
    char value;
    auto Get() { return value; }
};

struct M
{
    int value;
    auto Get() { return value; }
};

void func3( auto n )
    requires requires
{
    //{ n.Get() } -> std::same_as<int>;
    { n.value } -> std::same_as<int>;
}
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


void func3( auto n )
    requires requires 
{
    //{ n.Get() } -> std::same_as<char>;
    { n.value } -> std::same_as<char>;
}
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main()
{
    M m;
    N n;

    func3( n );
    func3( m );
}

导致(gcc 10.1.1)的消息多一些

main.cpp: In function 'int main()':
main.cpp:202:18: error: no matching function for call to 'func3(N&)'
  202 |         func3( n );
      |                  ^
main.cpp:154:10: note: candidate: 'void func3(auto:15) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, int>];} [with auto:15 = N]'
  154 |     void func3( auto n )
      |          ^~~~~
main.cpp:154:10: note: constraints not satisfied
main.cpp: In instantiation of 'void func3(auto:15) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, int>];} [with auto:15 = N]':
main.cpp:202:18:   required from here
main.cpp:154:10:   required by the constraints of 'template<class auto:15> void func3(auto:15) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, int>];}'
main.cpp:155:18:   in requirements  [with auto:15 = N]
main.cpp:158:13: note: 'n.value' does not satisfy return-type-requirement
  158 |         { n.value } -> std::same_as<int>;
      |           ~~^~~~~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
main.cpp:165:10: note: candidate: 'void func3(auto:16) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, char>];} [with auto:16 = N]'
  165 |     void func3( auto n ) 
      |          ^~~~~
main.cpp:165:10: note: constraints not satisfied
main.cpp: In instantiation of 'void func3(auto:16) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, char>];} [with auto:16 = N]':
main.cpp:202:18:   required from here
main.cpp:165:10:   required by the constraints of 'template<class auto:16> void func3(auto:16) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, char>];}'
main.cpp:166:18:   in requirements  [with auto:16 = N]
main.cpp:169:13: note: 'n.value' does not satisfy return-type-requirement
  169 |         { n.value } -> std::same_as<char>;
      |           ~~^~~~~
main.cpp:203:18: error: no matching function for call to 'func3(M&)'
  203 |         func3( m );
      |                  ^   
main.cpp:154:10: note: candidate: 'void func3(auto:15) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, int>];} [with auto:15 = M]'
  154 |     void func3( auto n ) 
      |          ^~~~~
main.cpp:154:10: note: constraints not satisfied
main.cpp: In instantiation of 'void func3(auto:15) requires requires{{func3::n.value} -> decltype(auto) [requires std::same_as<<placeholder>, int>];} [with auto:15 = M]':
main.cpp:203:18:   required from here

检查Get()函数返回类型的版本可以正常工作。怎么了?

请参见compiler explorer

  • c声:按预期工作
  • gcc 10.1.1失败,并显示错误消息
  • gcc主干:ICE! ubs:-)

2 个答案:

答案 0 :(得分:3)

GCC实际上是正确的(拒绝代码时,不要胡说八道)。引用标准

[expr.prim.req.compound] / 1.3

  • 如果存在return-type-requirement,则:
    • 执行将模板参数(如果有)替换为return-type-requirement。
    • 应满足decltype((E))的类型约束的立即声明的约束([temp.param])。

E是我们的表达,即n.value

现在,decltype(n.value)charint,这是因为decltype has a special rule for class member access and id expressions。但是decltype((n.value))char&int&。处理通用表达式(例如带括号的类成员访问权限)时,值类别以decltype的类型编码。

您的示例在修改后可以在GCC中使用

void func3( auto n )
    requires requires
{
    //{ n.Get() } -> std::same_as<int>;
    { n.value } -> std::same_as<int&>;
}
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


void func3( auto n )
    requires requires 
{
    //{ n.Get() } -> std::same_as<char>;
    { n.value } -> std::same_as<char&>;
}
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

答案 1 :(得分:0)

根据[expr.prim.req.compound]/1.3

如果存在返回类型要求,则:

  • 将模板参数(如果有)替换为return-type-requirement。

  • 应满足decltype((E))的类型约束的立即声明的约束([temp.param])。 [示例:给定 概念CD

    requires {
      { E1 } -> C;
      { E2 } -> D<A1, ⋯, An>;
    };
    

    等同于

    requires {
      E1; requires C<decltype((E1))>;
      E2; requires D<decltype((E2)), A1, ⋯, An>;
    };
    

    (包括n为零的情况)。 -结束示例 ]

并且从[dcl.type.decltype]/1开始,尤其是[dcl.type.decltype]/1.5

对于表达式E,由decltype(E)表示的类型定义为 如下:

  • [...]
  • (1.5),否则,如果E是左值,decltype(E)T& ,其中T是{{1 }};

因此,由于Evalue表达式中的lvalue,因此 return-type-requirement { n.value } -> std::same_as<int>;的类型约束-> std::same_as<...>;表达式需要与返回类型{ n.value }相匹配:

int&