【问题标题】:compiler differences when using std::enable_if in return type of templated member function在模板化成员函数的返回类型中使用 std::enable_if 时的编译器差异
【发布时间】:2018-09-23 16:12:34
【问题描述】:

我尝试为struct Node 中的一个方法定义两个“重载”,这取决于结构模板参数调用不同的行为。

我知道我可以使用其他方法(例如 if constexpr 或其他方法)..

我担心的是我“欺骗”了 gcc 9.0.0 实验版 20180919 来编译它,但 wandbox 中可用的所有其他最新编译器(下面的永久链接)都没有。我想 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();
}

https://wandbox.org/permlink/d2IaWwt9GJn31Wmq

【问题讨论】:

    标签: c++ templates gcc enable-if


    【解决方案1】:

    代码格式不正确,实验性 gcc 9.0.0 忽略它是错误的。

    了解 SFINAE 规则的关键在于,它适用于在将函数模板的参数替换为其他函数模板参数的默认模板实参或函数类型时形成无效类型或表达式的情况,如在[temp.deduct]段的介绍;或者在确定类模板的部分特化是否匹配或哪个部分特化最特化时。但是在您的代码中,无效类型是在替换类模板的参数LA而不是函数模板的参数时形成的。

    同样相关的是[temp.inst]/2段:

    类模板特化的隐式实例化原因

    • 非删除类成员函数、成员类、作用域成员枚举、静态数据成员、成员模板和朋友的声明的隐式实例化,但不是定义的隐式实例化;和

    • 已删除成员函数、无范围成员枚举和成员匿名联合的定义的隐式实例化。

    类模板特化的隐式实例化不会导致默认参数或类成员函数的 noexcept-specifier 的隐式实例化。

    由于mainxy 的定义要求Node&lt;lazy, AND&gt;Node&lt;nonlazy, OR&gt; 类型是完整的,因此必须为这两个特化实例化类模板。并且实例化类模板意味着实例化函数模板声明,因此在每种情况下,程序都是格式错误的,因为该声明包含非依赖的无效类型。


    旁注:正如您所提到的,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 的表达式约束是完全有效的,否则永远无法满足。这意味着它永远不会被视为重载解决方案的可行候选者。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      相关资源
      最近更新 更多