这不能编译:

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

  • 使用std::get,您可以通过索引而不是通过类型访问项目。


    – 

  • @edrezen 重载 5 至 8 允许按类型访问元组的元素:


    – 


  • 天哪,我错过了它,尽管有时我会需要它…所以这std::get<char>(std::tuple<int, double>{});没有编译是有道理的


    – 


  • 我不明白你的语法,它不是更像吗?(注意问题仍然存在)


    – 

  • 1
    user17732522 似乎已经回答了这个问题。如果您需要修复:(灵感来自


    – 


最佳答案
1

在检查需求的有效性时,只检查表达式的所谓直接上下文。

直接上下文不包含任何验证,即如果实际评估调用则必要的实例是否格式正确。

在这种情况下,如果为 指定的模板参数无效,则不会指定std::get的重载std::tuple从重载解析中排除。因此,重载解析将正常工作并选择重载。如果它未定义为已删除,则可以正常调用它。正如您看到的那样,它只是说如果模板参数不正确,则调用格式不正确。std::getstd::get<char>

实现可以使调用格式错误,而不是将其排除在重载解析之外的一种方法是将 添加static_assert到其主体以检查条件。然后,如果调用实际上显示为(潜在)求值的表达式,std::get<char>则将被隐式实例化,并且在该实例中static_assert将会失败,从而使实例化和程序格式错误。但是,格式错误是在 的实例化中std::get<char>,它不在要求中的表达式的直接上下文中。

这和你尝试对模板参数的有效性执行 SFINAE 时发生的情况完全相同std::get。它也永远不会失败。

对此的一个常用术语是“ SFINAE 友好性”。如果std::getstd::tupleSFINAE 友好的,那么它将被指定为当模板参数对于元组无效时,重载将被排除在重载解析之外,然后实现将需要添加约束,std::get以便重载解析不会认为重载在这种情况下可行。然后,调用表达式本身将格式错误,您的需求将能够检测到它。

2

  • 3
    所以 TL;DRstd::get对 SFINAE 并不友好。


    – 


  • –