简体   繁体   English

在模板化成员函数的返回类型中使用 std::enable_if 时的编译器差异

[英]compiler differences when using std::enable_if in return type of templated member function

I tried to define two "overloads" for a method in struct Node that, depending on the struct template parameter invoke different behaviours.我试图为struct Node中的一个方法定义两个“重载”,根据结构模板参数调用不同的行为。

I am aware that I could use other methods (like if constexpr or whatever)..我知道我可以使用其他方法(例如if constexpr或其他方法)。

My concern is that I "tricked" the gcc 9.0.0 experimental 20180919 into compiling this, but all the other recent compilers available in wandbox (permlink below) do not.我担心的是,我“欺骗”了 gcc 9.0.0 实验 20180919 来编译它,但是 wandbox(下面的 permlink)中可用的所有其他最新编译器都没有。 I suppose gcc8 and clang6/7 do the right thing here?我想 gcc8 和 clang6/7 在这里做正确的事?

Thanks for your help!谢谢你的帮助!

#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 https://wandbox.org/permlink/d2IaWwt9GJn31Wmq

The code is ill-formed, and that experimental gcc 9.0.0 is wrong to ignore it.代码格式错误,实验性 gcc 9.0.0 忽略它是错误的。

A key thing to understand about the SFINAE rule is that it applies when an invalid type or expression is formed while substituting a parameter of a function template into default template arguments for other function template parameters or into the function type, as described in the introduction of section [temp.deduct] ;理解 SFINAE 规则的一个关键点是,它适用于在将函数模板的参数替换为其他函数模板参数的默认模板参数或函数类型的同时形成无效类型或表达式时,如介绍中所述[temp.deduct]部分; or when determining whether a partial specialization of a class template matches or which partial specialization is most specialized.或者在确定类模板的部分特化是否匹配或哪个部分特化最特化时。 But in your code, the invalid type is formed while substituting the parameter LA of the class template, not a parameter of the function templates.但是在您的代码中,在替换类模板的参数LA时形成了无效类型,而不是函数模板的参数。

Also relevant is paragraph [temp.inst]/2 :同样相关的是[temp.inst]/2 段

The implicit instantiation of a class template specialization causes类模板特化的隐式实例化导致

  • the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends;未删除的类成员函数、成员类、作用域成员枚举、静态数据成员、成员模板和朋友的声明的隐式实例化,但不是定义的隐式实例化; and

  • the implicit instantiation of the definitions of deleted member functions, unscoped member enumerations, and member anonymous unions.已删除成员函数、无作用域成员枚举和成员匿名联合的定义的隐式实例化。

The implicit instantiation of a class template specialization does not cause the implicit instantiation of default arguments or noexcept-specifier s of the class member functions.类模板特化的隐式实例化不会导致类成员函数的默认参数或noexcept-specifier的隐式实例化。

Since the definitions of x and y within main require the types Node<lazy, AND> and Node<nonlazy, OR> to be complete, the class template must be instantiated for these two specializations.由于mainxy的定义要求类型Node<lazy, AND>Node<nonlazy, OR>是完整的,因此必须为这两个特化实例化类模板。 And instantiating the class template means instantiating the function template declarations, so in each case the program is ill-formed since that declaration contains a non-dependent invalid type.实例化类模板意味着实例化函数模板声明,因此在每种情况下程序都是格式错误的,因为该声明包含非依赖的无效类型。


Side note: As you mentioned, if constexpr is probably the simplest way to solve this sort of issue in C++17.旁注:正如您所提到的, if constexpr可能是在 C++17 中解决此类问题的最简单方法。 (The public function could just call one of two private functions with different names, if you desire to have the implementations separate.) But C++20 will introduce "constraints" for templates and functions which will provide an even nicer solution: (如果您希望将实现分开,公共函数可以只调用具有不同名称的两个私有函数之一。)但是 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;
    }
};

Unlike SFINAE tricks, it's entirely valid to have a member function constrained by an expression equivalent to false or which otherwise can never be satisfied.与 SFINAE 技巧不同,让成员函数受等价于false或永远无法满足的表达式约束是完全有效的。 This means it will never be considered a viable candidate for overload resolution.这意味着它永远不会被视为重载决议的可行候选者。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 enable_if 与类成员函数的返回类型 - enable_if with return type for class member function 正确使用std :: enable_if作为返回类型 - Correctly using std::enable_if as a return type 在模板化 class 的方法上使用 std::enable_if - using std::enable_if on a method of a templated class 使用std :: enable_if启用模板化的构造函数和一个返回另一个模板化实例的函数 - Using std::enable_if to enable a templated constructor and a function that returns another templated instance 将 std::enable_if 与外部成员函数和模板化静态成员条件一起使用 - Using std::enable_if with out-of-line member functions and templated static member conditions 在将decltype与带有尾随返回类型语法的模板化成员函数一起使用时,gcc中出现编译器错误,但没有clang - compiler error in gcc but not clang when using decltype with templated member function with trailing return type syntax std::enable_if 基于使用静态 constexpr 成员函数的表达式 - std::enable_if based on expression using static constexpr member function 成员函数的boost :: enable_if,重载返回类型 - boost::enable_if on member function, overload return type std::enable_if 有条件地编译成员 function - std::enable_if to conditionally compile a member function 使用 enable_if 时如何解决此错误:“struct std::enable_if 中没有名为 'type' 的类型<false, void> ’”</false,> - How to slove this error when using enable_if: “no type named ‘type’ in ‘struct std::enable_if<false, void>’”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM