14.8.2段的C++ 11标准的/ 8指定在其下的取代失败作出或不会导致"硬"编译错误的条件(从而引起编译失败),或者在"软"差错这将只是导致编译器从一组候选中丢弃模板以进行重载解析(不使编译失败并启用众所周知的SFINAE习语):
如果替换导致无效的类型或表达式,则类型推导失败.如果使用替换参数写入,则无效的类型或表达式将是格式错误的.[注意:访问检查是作为替换过程的一部分完成的.-end note] 只有函数类型的直接上下文中的无效类型和表达式及其模板参数类型才会导致演绎失败.[...]
单词" 直接上下文 "在整个C++ 11标准中仅出现8次,并且每次出现以下(或作为其一部分)以下(非规范)文本的实例时:
[注:在取代的类型和表达式的计算可导致副作用,例如类模板特和/或功能模板特的实例化,隐含定义的函数的生成等.这样的副作用是不是在"即时上下文"并且可能导致程序格式不正确. - 尾注]
该说明给出了什么叫一个(不是非常慷慨)暗示直接背景,但至少对我来说这往往是不足以决定一个替代是否是或不应该造成"硬"的编译错误.
题:
您能否提供一个解释,一个决策程序和/或一些具体的例子来帮助弄清楚在什么情况下替换错误在函数类型及其模板参数类型的" 直接上下文 "中发生和不发生?
考虑这个代码:
#include <tuple>
#include <type_traits>
#include <iostream>
template <typename T, typename = void> struct is_tuple_like : std::false_type {};
template <typename T> struct is_tuple_like<T, decltype(std::tuple_size_v<T>, void())> : std::true_type {};
int main()
{
std::cout << is_tuple_like<std::string>::value << '\n';
}
Run Code Online (Sandbox Code Playgroud)
在 GCC 10.2 和 MSVC 19.28 上,它会导致硬错误,如下所示:
#include <tuple>
#include <type_traits>
#include <iostream>
template <typename T, typename = void> struct is_tuple_like : std::false_type {};
template <typename T> struct is_tuple_like<T, decltype(std::tuple_size_v<T>, void())> : std::true_type {};
int main()
{
std::cout << is_tuple_like<std::string>::value …Run Code Online (Sandbox Code Playgroud) 考虑以下概念:
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 …Run Code Online (Sandbox Code Playgroud)