c++ - 当使用无效表达式时,概念是否应该编译失败?

标签 c++ c++-concepts

我正在尝试实现一种紧凑的方法来检测编译时是否有自由函数可用(我使用 std::max 作为示例)。我想到了这个:

#include <stdio.h>  
#include <algorithm>           // (1)

namespace std { struct max; }  // (2)

template<typename A>
concept bool have_std_max = requires(A const& a1, A const& a2) {
  { std::max(a1, a2) }
};

template <typename A> 
constexpr A const &my_max(A const &a1, A const &a2) {
  if constexpr(have_std_max<A>) {
    return std::max(a1, a2);
  }
  else {
    return (a1 > a2) ? a1 : a2;
  }
}

int main() {
  int x = 5, y = 6;
  return my_max(x, y);
}

如果我注释掉 (1),则检测有效并且我的代码使用 constexpr else 分支(参见 in Compiler Explorer)。但是,如果我注释掉 (1) 和 (2),这段代码将无法编译,因为名称 std::max 对编译器来说是未知的。在这种情况下,这个概念不应该简单地返回 false 吗?有没有一种方法可以在不必声明虚拟 max 的情况下实现类似的东西?

最佳答案

C++ 的模板系统绝不是编写错误代码的借口。模板只为所谓的依赖 类型和表达式提供余地。 (这是一个很长的话题,需要更深入地研究 in this answer。)为了我们的目的,一个限定名称的形式是 std::max。不涉及任何依赖项,因此它必须在出现的地方是正确的。反过来,这意味着查找必须成功。

您尝试添加 max 是在正确的轨道上声明。通过这样做,非依赖限定名总能成功地找到一个声明。同时,整体表达式仍然依赖(由于涉及 a0a1 )。剩下的就是避免污染 std命名空间,我们不允许这样做:

#include <algorithm>

namespace dirty_tricks {

namespace max_fallback {

// non-deducible on purpose
template<typename Dummy>
void max() = delete;

} // max_fallback

namespace lookup {

// order of directives is not significant
using namespace std;
using namespace max_fallback;

} // lookup

} // dirty_tricks

template<typename Val>
concept bool have_std_max = requires(Val arg) {
    // N.B. qualified call to avoid ADL
    dirty_tricks::lookup::max(arg, arg);
};

(通过删除 <algorithm> 测试代码时,请确保仍声明了 std 命名空间,否则 using 指令可能会失败。如本 Coliru demo 所示。)

现在dirty_tricks::lookup::max要么找到两个 std::maxdirty_tricks::max_fallback::max或单独使用后者,但它不会失败。我们还确保我们自己的 max重载不能通过删除它来产生有效的表达式(否则有效的调用看起来会非常不同)。

关于c++ - 当使用无效表达式时,概念是否应该编译失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42646399/

相关文章:

c++ - 他们如何在没有显式模型(又名概念图)的情况下避免基于概念的重载问题

c++ - STL 概念是否涵盖了 STL 算法的所有参数要求?

c++ - 有没有办法在 MSVC 输出中禁用 ".pdata"/"ExceptionDir"和 "UNWIND_INFO"?

c++ - 如何在 string_view 中推断出悬空指针?

c++ - 如何构建具有所有依赖项的 C++ 以在另一台机器上运行

c++ - Qt5.11应用程序插件构建错误: Signal and slot arguments are not compatible

c++ - 适用于 iOS 和 Android 的 QT C++ 中的 HTTPS 请求

c++ - 为什么在定义这个 C++ 概念时会出错?

c++ - void_t "can implement concepts"?

c++ - std::is_convertible和std::convertible_to(在实践中)之间的区别?