微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当一个条件分支从基类继承时,为什么这个 SFINAE 不能与 enable_if 一起工作?

如何解决当一个条件分支从基类继承时,为什么这个 SFINAE 不能与 enable_if 一起工作?

#include <bits/stdc++.h>
#include <type_traits>

// Type your code here,or load an example.
template <typename Types>
class C1 {
public:
    using A=typename Types::A;
    using B=typename Types::B;

    template <typename Dummy = void>
    inline typename std::enable_if<std::is_same<A,B>::value,Dummy>::type f() { }

};

template <typename Types>
class C2 : public C1<Types> {
public:
    using A=typename Types::A;
    using B=typename Types::B;

    template <typename Dummy = void>
    inline typename std::enable_if<!std::is_same<A,Dummy>::type f() { }

};

template <typename Types>
class C3 : public C2<Types> {
public:
    using A=typename Types::A;
    using B=typename Types::B;
};


struct Types{
    using A = int;
    using B = int;
};

int main() {
    C3<Types> c;
    c.f();
    return 0;
}

当我尝试在 A 和 B 不相同的情况下编译上述代码时,出现以下错误

<source>: In function 'int main()':
<source>:42:9: error: no matching function for call to 'C3<Types>::f()'
   42 |     c.f();
      |         ^
<source>:23:77: note: candidate: 'template<class Dummy> typename std::enable_if<(! std::is_same<typename Types::A,typename Types::B>::value),Dummy>::type C2<Types>::f() [with Dummy = Dummy; Types = Types]'
   23 |     inline typename std::enable_if<!std::is_same<A,Dummy>::type f() { }
      |                                                                             ^
<source>:23:77: note:   template argument deduction/substitution Failed:
<source>: In substitution of 'template<class Dummy> typename std::enable_if<false,Dummy>::type C2<Types>::f<Dummy>() [with Dummy = void]':
<source>:42:9:   required from here
<source>:23:77: error: no type named 'type' in 'struct std::enable_if<false,void>'

请注意,我提供的代码不是我使用的确切代码,而是一个最小的可重现示例

编辑:使用godbolt代替之前的示例,提供一个可重现的最小示例,以便更好地了解情况

解决方法

与此类问题一样,它归结为 SFINAE 的定义。 S 代表“替换”,它发生在我们试图实例化的模板中。该模板是成员 f,而不是 C

尽管 C 也是一个模板,并且 AB 都是 C 中的依赖类型,但它们不是依赖类型当 f 被实例化时。他们已经是众所周知的了。因此,条件 std::is_same<A,B>::value 的值不依赖于 f 的任何模板参数。它不依赖变电站进入f。这会导致 C++11 标准中的以下条款(取自发布前的最后一个草案):

[temp.res](强调我的)

8 知道哪些名称是类型名称允许每个 要检查的模板定义。不得发布诊断报告 可以为其生成有效专业化的模板定义。 如果无法为模板定义生成有效的特化,并且该模板未实例化,则模板 定义格式错误,无需诊断

这意味着无论 Types 是什么,如果它不支持 f 的条件,那么 f 的定义(甚至没有被实例化),已经是病态的——每当 C 实例化时形成。通常不需要对此进行诊断(因为在一般情况下检查它是难以处理的),但编译器可以足够早地对其进行诊断,并且会告诉您问题所在。

现在,至于如何修复它,只需使 f 值的条件依赖于它自己的模板参数。一个简单的重写就可以

template <bool Dummy = std::is_same<A,B>::value>
inline auto f(vector<int>& ctx,const string& r) -> 
  typename std::enable_if<Dummy>::type { }

现在条件取决于正确上下文中的变电站。


当然,即使您修复了 SFIANE 问题,您仍然需要确保重载集由正确的成员组成。 f 中的 C2 隐藏了 f 中的 C1。向 C2 添加 using 声明,使其仍然是候选者

using C1<Types>::f;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。