[英]compiler differences when using std::enable_if in return type of templated member function
我试图为struct Node
中的一个方法定义两个“重载”,根据结构模板参数调用不同的行为。
我知道我可以使用其他方法(例如if constexpr
或其他方法)。
我担心的是,我“欺骗”了 gcc 9.0.0 实验 20180919 来编译它,但是 wandbox(下面的 permlink)中可用的所有其他最新编译器都没有。 我想 gcc8 和 clang6/7 在这里做正确的事?
谢谢你的帮助!
#include <iostream>
#include <type_traits>
enum laziness { lazy, nonlazy };
enum logic { AND, OR };
template<laziness LA, logic LO>
struct Node{
template<typename = void>
std::enable_if_t<LA==lazy> printLaziness () const {
std::cout << "lazy" << std::endl;
}
template<typename = void>
std::enable_if_t<LA==nonlazy> printLaziness () const {
std::cout << "non-lazy" << std::endl;
}
};
int main () {
Node<lazy, AND> x{};
x.printLaziness();
Node<nonlazy, OR> y{};
y.printLaziness();
}
代码格式错误,实验性 gcc 9.0.0 忽略它是错误的。
理解 SFINAE 规则的一个关键点是,它适用于在将函数模板的参数替换为其他函数模板参数的默认模板参数或函数类型的同时形成无效类型或表达式时,如介绍中所述[temp.deduct]部分; 或者在确定类模板的部分特化是否匹配或哪个部分特化最特化时。 但是在您的代码中,在替换类模板的参数LA
时形成了无效类型,而不是函数模板的参数。
同样相关的是[temp.inst]/2 段:
类模板特化的隐式实例化导致
未删除的类成员函数、成员类、作用域成员枚举、静态数据成员、成员模板和朋友的声明的隐式实例化,但不是定义的隐式实例化; 和
已删除成员函数、无作用域成员枚举和成员匿名联合的定义的隐式实例化。
s of the class member functions.类模板特化的隐式实例化不会导致类成员函数的默认参数或的隐式实例化。
由于main
中x
和y
的定义要求类型Node<lazy, AND>
和Node<nonlazy, OR>
是完整的,因此必须为这两个特化实例化类模板。 实例化类模板意味着实例化函数模板声明,因此在每种情况下程序都是格式错误的,因为该声明包含非依赖的无效类型。
旁注:正如您所提到的, if constexpr
可能是在 C++17 中解决此类问题的最简单方法。 (如果您希望将实现分开,公共函数可以只调用具有不同名称的两个私有函数之一。)但是 C++20 将为模板和函数引入“约束”,这将提供更好的解决方案:
template<laziness LA, logic LO>
struct Node{
void printLaziness () const requires (LA==lazy) {
std::cout << "lazy" << std::endl;
}
void printLaziness () const requires (LA==nonlazy) {
std::cout << "non-lazy" << std::endl;
}
};
与 SFINAE 技巧不同,让成员函数受等价于false
或永远无法满足的表达式约束是完全有效的。 这意味着它永远不会被视为重载决议的可行候选者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.