提问人:CakePlusPlus 提问时间:7/13/2023 更新时间:7/13/2023 访问量:251
为什么在这种情况下需要always_false_v?
Why is always_false_v required in this situation?
问:
我正在用于指定项目中实体可能具有的属性类型,并偶然发现了 cpppreference 中的这段代码:std::variant
std::visit([](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>)
std::cout << "int with value " << arg << '\n';
else if constexpr (std::is_same_v<T, long>)
std::cout << "long with value " << arg << '\n';
else if constexpr (std::is_same_v<T, double>)
std::cout << "double with value " << arg << '\n';
else if constexpr (std::is_same_v<T, std::string>)
std::cout << "std::string with value " << std::quoted(arg) << '\n';
else
static_assert(always_false_v<T>, "non-exhaustive visitor!");
}, w);
always_false_v
定义为
template<class>
inline constexpr bool always_false_v = false;
我知道这会在编译时检查我是否正在处理我的变体中的所有类型,这非常酷且有用,但我对为什么需要感到困惑。always_false_v<T>
如果我从 s 中删除一个分支,Visual Studio 中的智能感知会立即设置红色波浪线,因为 失败。if
static_assert
如果我替换为 ,intellisense 不会抱怨,但当我尝试构建时,静态断言会失败。always_false_v<T>
false
为什么还不够?我希望即使在编译时也永远不会执行,如果它一直执行,为什么不等价(看起来它肯定不可能)?false
else
always_false_v<T>
false
true
答:
这里讨论这个问题。乔纳森·韦克利(Jonathan Wakely)的回答特别有用。
简而言之,因为使程序格式不正确,如果将程序放在模板或语句的分支中,则意味着该模板或该分支的每个可能的实例化都会使程序格式不正确。当编译器看到一个模板或分支时,每个可能的实例化都格式不正确,即使此类实例化从未发生过,它也可以拒绝程序。static_assert(false)
static_assert(false)
if constexpr
if constexpr
if constexpr
但是,当您有 form 的构造时,并不是每个可能的实例化都会使其格式不正确。可能有一些专业化,这是真的。当然,在你的程序中,你没有这样的专业化,但关键是你可以引入一个,它可能是在引用它的模板的定义之后。因为不满足“不可能的实例化格式良好”标准,所以它避免了 .static_assert(always_false_v<T>);
always_false_v
static_assert(always_false<T>)
static_assert(false)
使整个模板格式不正确的事实特别令人讨厌,因为早期诊断实际上对程序员没有帮助。出于这个原因,C++23 中的规则已经更改,为静态断言提供了特殊的豁免:现在只有在实际实例化程序时才会使程序格式错误。static_assert(false)
static_assert(false)
static_assert(false, ...)
总是被评估,所以总是会立即失败。您需要将第一个参数依赖于模板计算,以便仅当其他分支的计算结果为 false 时才对其进行评估。if
有关更深入的解释,请参阅Raymond Chen关于此主题的博客文章:
简而言之:
我必须做的一件事是,如果 lambda 调用不正确,则防止编译成功。我对有效案例进行了一系列测试,我需要在上面写着“你永远不应该到这里”上写一个。
if constexpr
static_assert
else
...
但是,这不会编译,因为 [] 会立即失败。
static_assert(false,...)
原因是 的控制表达式不依赖于参数的类型,因此在编译 lambda 时计算它,而不是在调用 lambda(和实例化隐式模板)时计算它。
static_assert
为了推迟实例化,我们需要使其依赖于类型。
static_assert
评论