让我们说,给定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中的错误,还是预期的行为?
答案 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>
}
答案 2 :(得分:0)
它从C ++ 2a和gcc 10开始工作: https://wandbox.org/permlink/qH34tI6oRJ3Ck7Mm