在嵌套模板中,`requires`表达式被评估为false,但代码仍然被编译。

16
我不明白在嵌套模板中如何使用requires关键字。
下面的代码可以在最新版本的MSVC和gcc上编译(分别使用/std:c++latest-std=c++2a)。
在这种情况下,requires是否被简单地丢弃了?我不应该这样使用吗?
#include <type_traits>

template <
    template < typename >
    requires (false) // Should not this stop compilation?
    typename Wrapper >
using Test = Wrapper < int >;

template < typename >
struct S
{
};

int main() {
    Test < S > var;

    return 0;
}

1
你尝试过其他编译器是否与MSVC一致吗?(Godbolt编译器资源管理器非常好用) - Marcus Müller
1
无关的提示:如果代码在使用-std=c++20编译时无法通过,那么你的GCC安装可能并不像你想象的那样最新。 - user4581301
1
@TedLyngmo 但似乎是因为错误的原因。我认为在 Clang 抱怨的地方有 requires-clause 并没有任何问题。但是编译应该失败,因为 Wrapper < int > 不满足 Wrapper 的约束条件(至少直觉上是这样)。 - user17732522
@TedLyngmo 这只是一个模板模板参数,它像任何其他模板一样具有 requires 子句。当然,requires(false) 具体来说没有太多意义(甚至可能是 IFNDR,我不知道),但是想象一下它是 template < typename T > requires std::same_as<float, T> typename Wrapper - user17732522
顺便提一下,我相信标志-std=c++2a是编译器使用的临时标志,允许您选择C++20的WIP功能(类似于C++23的-std=c++2b),当可用时,完整功能将通过-std=c++20激活。查看cppreference的C++20编译器支持页面,似乎只有GCC 10、Clang 10完全支持Concepts,并且仅由MSVC 19.23-19.30部分支持。因此,您正在使用的任何编译器版本可能尚未完全支持概念。 - oraqlle
显示剩余3条评论
1个回答

7
我认为编译器没有正确实现,你是正确的,它应该无法编译。
[temp.names]/7中,它说如果所有模板参数都是非相关的,则从带有约束条件的模板模板参数形成的template-id必须满足这些约束条件。
你只给了Wrapper一个参数,即int,它不是相关的。因此,编译器应该检查Wrapper<int>是否满足Wrapper的约束条件requires(false)。这个检查应该失败。
我不完全确定requires(false)是否特别是IFNDR,因为有一些类似的规则禁止例如永远无法实例化的模板,但编译器似乎在使用非平凡约束时表现相同。
Clang抱怨requires子句在那个位置上是语法错误,但我没有看到任何理由。
MSVC实际上处理以下变体,使用类型约束而不是requires-clause,如预期所示:
template<
    template<std::same_as<float> T>
    typename Wrapper>
using Test = Wrapper<int>;

但是如果使用requires子句,它不会像预期的那样拒绝。
template<
    template<typename T>
    requires std::same_as<float, T>
    typename Wrapper>
using Test = Wrapper<int>;

有趣的是,Clang在前者上崩溃并出现了内部编译器错误。

有些类似的问题:https://dev59.com/5sHqa4cB1Zd3GeqP36Bz - Fedor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接