代码之家  ›  专栏  ›  技术社区  ›  0xd34df00d

if constexpr和requires表达式用于特殊概念检查

  •  14
  • 0xd34df00d  · 技术社区  · 7 年前

    if constexpr 和概念TS(例如,在最近的gcc版本中),我们想检查模板函数中的类型是否具有嵌套类型:

    #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 呼叫似乎可以合理预期requires条款的评估结果为 false else 分公司 如果constexpr 将被拿走。与此相反,gcc使这成为一个硬错误:

    prog.cc: In instantiation of 'void doSmth(T) [with T = int]':
    prog.cc:17:13:   required from here
    prog.cc:8:5: error: 'int' is not a class, struct, or union type
         if constexpr (requires { typename T::Bar; })
         ^~
    

    这是gcc中的一个bug,还是预期的行为?

    3 回复  |  直到 7 年前
        1
  •  7
  •   Columbo    7 年前

    概念 issue 3 (“允许 需要表达式 从目前的情况来看 [expr.prim.req] ,尤其是p6:

    将模板参数替换为 需要表达式 需要表达式 false ; 它不会导致程序格式错误。

    我想说你的代码很好,GCC没有正确实现问题3的解决方案。

        2
  •  4
  •   Amir Kirsh    4 年前

    下面是一个使用 concept 在…内 if constexpr 用于检查类型是否具有方法 具有特定返回类型 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 GCC in Clang

        3
  •  3
  •   Dmitry Sychov    5 年前

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