当其中一个函数未编译时,函数重载查找如何工作?
How function overload lookup works when one of the functions does not compile?
所以我很不明白编译器是如何选择函数重载的。我以为我明白了这段代码:
#include <iostream>
using namespace std;
template<class T>
struct base_type:
public T
{
};
template<class T>
void check(T (&)[sizeof(base_type<T>)/sizeof(base_type<T>)]) {std::cout << "yeah";}
template<class T>
void check(T) {std::cout << "nah";}
union U{};
struct S{};
int main()
{
U u[1];
S s[1];
check(u); // compile error
check(s);
return 0;
}
为什么编译器没有选择 check(T)
的 2d 重载,因为它无法检查拳头重载中的数组引用的大小?
SFINAE 出现在声明处,而不是定义处,base_type<U>
的声明很好,但会为其定义产生硬错误。
标准提供特征 std::is_union
和 std::enable_if
来做 SFINAE:
template<class T, std::enable_if_t<!std::is_union<T>::value, int> = 0>
void check(T (&)[1]) {std::cout << "yeah";}
对于 C++17,您甚至可以直接在函数内部使用 if constexpr
(即使简单的 if
在您的简化情况下也可以):
template<class T>
void check(T (&)[1])
{
if constexpr(std::is_union<T>::value) {
std::cout << "nah";
} else {
std::cout << "yeah";
}
}
只有来自 immediate context 的错误会导致 "soft" 错误,从而将函数模板从重载集中删除。编译器必须先实例化 base_type<T>
,然后才能计算 sizeof(base_type<T>)
,并且该实例化导致的任何错误在直接上下文中都是 而不是 ,并导致硬错误。
我不确定你到底想做什么,但你可以使用 std::enable_if_t<std::is_union_v<T>>
来禁用过载。这样做的原因是首先完成的 std::enable_if
的实例化不会导致错误;结果 class 可能根本不包含名为 type
的成员。对 type
的访问是 在直接上下文中。
我还找到了可能支持答案的标准引述。
标准引用,C++11 §14.8.2/8:
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a
deduction failure. [ Note: The evaluation of the substituted types and
expressions can result in side effects such as the instantiation of
class template specializations and/or function template
specializations, the generation of implicitly-defined functions, etc.
Such side effects are not in the “immediate context” and can result in
the program being ill-formed. — end note ]
所以我很不明白编译器是如何选择函数重载的。我以为我明白了这段代码:
#include <iostream>
using namespace std;
template<class T>
struct base_type:
public T
{
};
template<class T>
void check(T (&)[sizeof(base_type<T>)/sizeof(base_type<T>)]) {std::cout << "yeah";}
template<class T>
void check(T) {std::cout << "nah";}
union U{};
struct S{};
int main()
{
U u[1];
S s[1];
check(u); // compile error
check(s);
return 0;
}
为什么编译器没有选择 check(T)
的 2d 重载,因为它无法检查拳头重载中的数组引用的大小?
SFINAE 出现在声明处,而不是定义处,base_type<U>
的声明很好,但会为其定义产生硬错误。
标准提供特征 std::is_union
和 std::enable_if
来做 SFINAE:
template<class T, std::enable_if_t<!std::is_union<T>::value, int> = 0>
void check(T (&)[1]) {std::cout << "yeah";}
对于 C++17,您甚至可以直接在函数内部使用 if constexpr
(即使简单的 if
在您的简化情况下也可以):
template<class T>
void check(T (&)[1])
{
if constexpr(std::is_union<T>::value) {
std::cout << "nah";
} else {
std::cout << "yeah";
}
}
只有来自 immediate context 的错误会导致 "soft" 错误,从而将函数模板从重载集中删除。编译器必须先实例化 base_type<T>
,然后才能计算 sizeof(base_type<T>)
,并且该实例化导致的任何错误在直接上下文中都是 而不是 ,并导致硬错误。
我不确定你到底想做什么,但你可以使用 std::enable_if_t<std::is_union_v<T>>
来禁用过载。这样做的原因是首先完成的 std::enable_if
的实例化不会导致错误;结果 class 可能根本不包含名为 type
的成员。对 type
的访问是 在直接上下文中。
我还找到了可能支持答案的标准引述。
标准引用,C++11 §14.8.2/8:
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]