当从基础类继承一个条件分支时,为什么此SFINAE不能与enable_if一起使用? [英] Why does this SFINAE not work with enable_if when one conditional branch is inherited from the base class?

查看:57
本文介绍了当从基础类继承一个条件分支时,为什么此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, 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;
}

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

When I try to compile the above code when A and B are not same, I get the following error:

<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

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

EDIT: Put up a minimal reproducible example using godbolt in place of the earlier for a better understanding of the situation

推荐答案

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

As always with such problems, it falls down to the very definition of SFINAE. The S stands for "substitution", which happens into the template that we are trying to instantiate. That template is the member f, and not C.

即使 C 也是模板,并且 A B 都是 C 中的依赖类型,当实例化 f 时,它们是 not 依赖类型.他们已经知道了.这样,条件 std :: is_same< A,B> :: value 的值不取决于 f 的任何模板参数.它不依赖于 f 的变电站.这会触发C ++ 11标准中的以下子句(摘自发布前的最新草案):

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. They are already known. As such, the condition std::is_same<A, B>::value is not value dependent on any template parameter of f. It doesn't depend on substation into f. This trips the following clause in the C++11 standard (taken from the last draft prior to publication):

[temp.res] (强调我的意思)

8 知道哪些名称是类型名称可以每个的语法要检查的模板定义.对于以下情况,不得发布诊断信息:可以为其生成有效专业化的模板定义.如果无法为模板定义生成有效的专业化,并且该模板未实例化,则该模板定义格式错误,无需诊断.

8 Knowing which names are type names allows the syntax of every template definition to be checked. 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.

这意味着无论 Types 是什么,如果它不支持 f 的条件,则 f 的定义(不包含甚至被实例化),无论何时实例化 C ,都已经格式错误.通常,不需要进行诊断(因为在一般情况下检查起来很棘手),但是编译器可以足够早地对其进行诊断,并会告诉您问题所在.

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. 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.

现在,关于如何修复它,只需使 f 值的条件取决于其自身的模板参数即可.一个简单的重写可以是

Now, as to how to fix it, just make the condition of f value dependent on its own template parameter. 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.

当然,即使解决了SFIANE问题,您仍然需要确保过载集由正确的成员组成. C2 中的 f 隐藏 C1 中的 f .在 C2 中添加using声明,使其仍然是候选对象

Of course, even if you fix the SFIANE problem, you still need to make sure the overload set is composed of the correct members. The f in C2 hides the f in C1. Add a using declaration to C2 so it's still a candidate

using C1<Types>::f;

这篇关于当从基础类继承一个条件分支时,为什么此SFINAE不能与enable_if一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆