我正在尝试找到一种方法来检查 lambda 是否可以不断评估或 不在 C++17 中。假设我要检查的 lambda 不带 参数。
我偶然发现 这个 问题,其接受的答案如下所示:
template <class Lambda, int = (Lambda{}(), 0)>
constexpr std::true_type is_cx_invocable(Lambda) {
return {};
}
constexpr std::false_type is_cx_invocable(...) {
return {};
}
其中存在以下问题:
它只适用于 C++20(因为默认需要无捕获的 lambda 可构造),我正在寻找 C++17 解决方案;
如果
is_cx_invocable
返回false
,不清楚是不是问题
Lambda
不是默认可构造的或其调用运算符不是 constexpr
,例如:
int main() {
static_assert(is_cx_invocable([] { return 0; }));
int i{};
auto cxLambda = [i] { return 0; };
(std::array<int, cxLambda()>{}, (void)0);
// ^ cxLambda is indeed constexpr invocable
// (but not default constructible)
auto isCxLambdaCx = is_cx_invocable(cxLambda);
static_assert(!isCxLambdaCx); // This fails
}
所以,我尝试了这个:
template <class Lambda>
constexpr auto is_cx_invocable(Lambda lambda)
-> std::integral_constant<bool, (lambda(), 1)> { // or
//-> std::enable_if_t<(lambda(), 1), std::true_type> {
return {};
}
constexpr std::false_type is_cx_invocable(...) {
return {};
}
哪个:
不需要 C++20 特性;
修复上面的问题(2):
int main() {
int i{};
auto cxLambda = [i] { return 0; };
auto isCxLambdaCx = is_cx_invocable(cxLambda);
static_assert(isCxLambdaCx); // OK now
}
问题是这个解决方案可以很好地与 Clang 和 MSVC 编译,但失败了 在 GCC 上编译。 在这里你是一个编译器 explorer链接玩。
我的问题是:
我的解决方案是否格式错误(因此 GCC 拒绝我的代码是正确的)?
是否有一个可移植的(即可以用 ISO C++ 实现并且独立于 编译器怪癖)来实现 C++17 中的
is_cx_invocable
检查?
有一条规则,函数参数不应被同一函数的默认参数潜在地评估:[dcl.fct.default]/9.
不过,好像GCC太严格了。它似乎在强制执行一条规则,即在主体开始之前不得评估函数参数(即您不能在尾随返回类型中执行此操作)。
所以我认为 Clang 和 MSVC 在这里是正确的。事实上,标准中没有任何规则会导致此示例格式错误。
(我也撤回了我原来答案的后半部分,因为这似乎是由于我的误解。您描述的元编程技术应该有效。)