在概念约束中使用变量模板会产生编译错误

Rer*_*ito 3 c++ templates c++-concepts c++20

考虑以下概念:

template< typename T, std::size_t Value >
concept Is_ = requires(T&&)
{
    requires Value == std::remove_cvref_t< T >::value;
};
Run Code Online (Sandbox Code Playgroud)

与函数重载相关:

template< Is_< 2 > T >
void foo(T&&)
{
    std::cout << "Value is 2!" << std::endl;
}

template< typename T >
void foo(T&&)
{
    std::cout << "Either no value or it isn't 2!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

最后,我们来玩一下上面的函数:

foo(std::integral_constant< std::size_t, 2 >{}); // Choose the constrained overload
foo(std::tuple{}) // Choose the generic impl
Run Code Online (Sandbox Code Playgroud)

现在,如果我定义以下辅助变量模板:

template< typename T >
inline constexpr auto t_value = T::value;
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,在概念中使用它:

template< typename T, std::size_t Value >
concept Is_ = requires(T&&)
{
    requires Value == t_value< std::remove_cvref_t< T > >;
};
Run Code Online (Sandbox Code Playgroud)

我现在得到这个编译器错误:

main.cpp:在“constexpr const auto t_value”的实例化中:

main.cpp:11:23:需要替换“模板需要 Is_<T, 2> void foo(T&&) [with T = int]”

main.cpp:27:8:从这里需要

main.cpp:6:29: 错误:“value”不是“int”的成员

6 | constexpr 自动 t_value = T::value;

然而,拥有无效的类型别名是完全没问题的。

MVCE 可在此处获取:https://coliru.stacked-crooked.com/a/653bb52448ca1db3

这种行为从何而来?

Sto*_*ica 5

发生这种情况是因为在替换和验证变量模板时,变量模板的实例化不在概念的“直接上下文”中。无效类型和表达式仅(并且始终)在它们出现的模板参数替换的直接上下文中是 sfinae 友好的。

由于t_value是完全不同的模板,因此在其实例化过程中发生的任何故障都不会是使用其专业化之一的概念中的“软故障”。


顺便说一下,要解决您帖子中的原始链接。别名模板有特殊的规定,通常允许它们成为一个直接替代品,无论它们的别名是什么,都会出现(想想看,std::enable_if_tsfinae 也很友好,而且一直都是)。当您在值之前检查t_value_typeconecpt 中的别名时,它已经以 sfinae 友好的方式失败了,因此该概念评估为 false(因为约束是按出现顺序检查的)。