这不能编译:
std::get<char>(std::tuple<int, double>{});
然而,其计算结果为true
。
template<typename T, typename V>
concept HasV = requires () {
std::get<char>(std::tuple<int, double>{});
};
我的理解是,上述概念会检查代码是否可编译,false
如果不可编译则进行评估。然而这里似乎并非如此。
现场演示在此: https:
6
最佳答案
1
在检查需求的有效性时,只检查表达式的所谓直接上下文。
直接上下文不包含任何验证,即如果实际评估调用则必要的实例是否格式正确。
在这种情况下,如果为 指定的模板参数无效,则不会指定std::get
的重载std::tuple
从重载解析中排除。因此,重载解析将正常工作并选择重载。如果它未定义为已删除,则可以正常调用它。正如您看到的那样,它只是说如果模板参数不正确,则调用格式不正确。std::get
std::get<char>
实现可以使调用格式错误,而不是将其排除在重载解析之外的一种方法是将 添加static_assert
到其主体以检查条件。然后,如果调用实际上显示为(潜在)求值的表达式,std::get<char>
则将被隐式实例化,并且在该实例中static_assert
将会失败,从而使实例化和程序格式错误。但是,格式错误是在 的实例化中std::get<char>
,它不在要求中的表达式的直接上下文中。
这和你尝试对模板参数的有效性执行 SFINAE 时发生的情况完全相同std::get
。它也永远不会失败。
对此的一个常用术语是“ SFINAE 友好性”。如果std::get
是std::tuple
SFINAE 友好的,那么它将被指定为当模板参数对于元组无效时,重载将被排除在重载解析之外,然后实现将需要添加约束,std::get
以便重载解析不会认为重载在这种情况下可行。然后,调用表达式本身将格式错误,您的需求将能够检测到它。
2
-
3所以 TL;DR
std::get
对 SFINAE 并不友好。
– -
–
|
std::get
,您可以通过索引而不是通过类型访问项目。–
–
std::get<char>(std::tuple<int, double>{});
没有编译是有道理的–
–
–
|