简体   繁体   English

当一个条件分支从基础 class 继承时,为什么此 SFINAE 不能与 enable_if 一起使用?

[英]Why does this SFINAE not work with enable_if when one conditional branch is inherited from the base class?

#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, B>::value, 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;
}

When I try to compile the above code when A and B are not same, I get the following error:当我在 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, B>::value, 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>'

Note that the code I have presented is not the exact code I use but a minimal reproducible example请注意,我提供的代码不是我使用的确切代码,而是一个最小的可重现示例

EDIT : Put up a minimal reproducible example using godbolt in place of the earlier for a better understanding of the situation编辑:使用godbolt代替前面的一个最小的可重复示例,以便更好地了解情况

As always with such problems, it falls down to the very definition of SFINAE.与此类问题一样,它归结为 SFINAE 的定义。 The S stands for "substitution", which happens into the template that we are trying to instantiate. S 代表“替换”,它发生我们试图实例化的模板中。 That template is the member f , and not C .该模板是成员f ,而不是C

Even though C is a template also, and both A and B are dependent types in C , they are not dependent type when f is instantiated.尽管C也是一个模板,并且AB都是C中的依赖类型,但在实例化f时它们不是依赖类型。 They are already known.他们已经为人所知。 As such, the condition std::is_same<A, B>::value is not value dependent on any template parameter of f .因此,条件std::is_same<A, B>::value不依赖于f的任何模板参数的值。 It doesn't depend on substation into f .它不依赖于f的变电站。 This trips the following clause in the C++11 standard (taken from the last draft prior to publication):这会触发 C++11 标准中的以下条款(取自发布前的最后草案):

[temp.res] (emphasis mine) [temp.res] (强调我的)

8 Knowing which names are type names allows the syntax of every template definition to be checked. 8知道哪些名称是类型名称可以检查每个模板定义的语法。 No diagnostic shall be issued for a template definition for which a valid specialization can be generated.对于可以生成有效特化的模板定义,不应发出诊断。 If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required .如果无法为模板定义生成有效的特化,并且该模板未实例化,则模板定义格式错误,无需诊断

This means that whatever Types is, if it doesn't uphold the condition of f , then the very definition of f (without even being instatiated), is already ill-formed whenever C is instantiated.这意味着无论Types是什么,如果它不支持f的条件,那么每当实例化C时, f的定义(甚至没有被实例化)就已经是不正确的。 A diagnostic is not required for this in general (since checking it is intractable in the general case), but compilers can diagnose it early often enough, and will tell you about the problem.通常不需要诊断(因为在一般情况下检查它是棘手的),但编译器可以经常及早诊断它,并会告诉你问题。

Now, as to how to fix it, just make the condition of f value dependent on its own template parameter.现在,至于如何修复它,只需使f值的条件依赖于它自己的模板参数即可。 A simple re-write can be一个简单的重写可以

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

Now the condition depends on substation in the correct context.现在条件取决于正确上下文中的变电站。


Of course, even if you fix the SFIANE problem, you still need to make sure the overload set is composed of the correct members.当然,即使您修复了 SFINE 问题,您仍然需要确保重载集由正确的成员组成。 The f in C2 hides the f in C1 . C2中的f隐藏了C1中的f Add a using declaration to C2 so it's still a candidateC2添加 using 声明,因此它仍然是候选者

using C1<Types>::f;

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM