if constexpr和requires-expression用于ad-hoc概念检查

时间:2017-11-06 19:32:14

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

让我们说,给定C ++ 17的if constexpr和Concepts TS(例如,在最近的gcc版本中),我们想检查一个类型是否存在template函数有一个嵌套类型:

#include <iostream>

struct Foo { using Bar = int; };

template<typename T>
void doSmth(T)
{
    if constexpr (requires { typename T::Bar; })
        std::cout << "has nested! " << typename T::Bar {} << std::endl;
    else
        std::cout << "no nested!" << std::endl;
}

int main()
{
    doSmth(Foo {});
    //doSmth(0);
}

概念的文档很少,所以我可能错了,但看起来就是这样(并且实例是Wandbox)。

现在让我们考虑在取消注释其他doSmth电话时会发生什么。似乎有理由期望require-clause将评估为false,并且else的{​​{1}}分支将被采用。与此相反,gcc使这成为一个很难的错误:

if constexpr

这是gcc中的错误,还是预期的行为?

3 个答案:

答案 0 :(得分:4)

概念issue 3(&#34;允许 require-expression 在更多情境中&#34;)在6月获得WP状态。并根据[expr.prim.req]的当前外观来判断,特别是p6:

  

将模板参数替换为 requires-expression 可能会导致在其要求中形成无效的类型或表达式,或者违反这些要求的语义约束。在这种情况下, requires-expression 评估为false;它不会导致程序格式不正确。

我说您的代码没问题,GCC没有正确实施问题3的解决方案。

答案 1 :(得分:4)

这是一个在concept内使用if constexpr来检查类型是否具有方法 foo 和特定返回类型 T 的工作示例。作为模板参数提供:

template<class P, class T>
concept Fooable = requires(P p) {
    requires std::same_as<decltype(p.foo()), T>;
};

template<typename T>
void printIsFooable(const auto& p) {
    if constexpr( Fooable<decltype(p), T> ) {
        std::cout << "fooable <" << typeid(T).name() << ">" << std::endl;
    }
    else {
        std::cout << "not fooable <" << typeid(T).name() << ">" << std::endl;
    }
}

struct MyFoo {
    void foo() const {}
};

int main() {
    printIsFooable<void>(MyFoo{}); // fooable <v>
    printIsFooable<int>(MyFoo{});  // not fooable <i>
    printIsFooable<void>(int{});   // not fooable <v>
}

代码使用C ++ 20 in GCCin Clang进行编译。

答案 2 :(得分:0)

它从C ++ 2a和gcc 10开始工作: https://wandbox.org/permlink/qH34tI6oRJ3Ck7Mm