c++ - SFINAE : What is happening here?

标签 c++

我目前正在尝试理解 C++ 代码,并且遇到了 SFINAE 构造(这对我来说是新的)。我创建了一个最小的示例,基于我在下面查看的代码:

#include<iostream>

/* ----------------------------------------------
 Define two kernels: characterized by their dimension
   ---------------------------------------------- */
struct Kern2
{
  static constexpr int dim = 2;
};

struct Kern3
{
  static constexpr int dim = 3;
};

/* ----------------------------------------------
 Choose which function to evaluate based on 
 dimension of Kern (Kern::dim)
   ---------------------------------------------- */
template<class Kern,
         typename std::enable_if<Kern::dim == 2, bool>::type = true>
inline void apply_kern(){
  std::cout << "dim=2" << "\n";
}

template<class Kern,
         typename std::enable_if<Kern::dim == 3, bool>::type = false>
inline void apply_kern(){
  std::cout << "dim=3" << "\n";
}

// Try to see if the above SFINAE construct works!
int main()
{

 apply_kern<Kern2>(); // should print 'dim=2'
 apply_kern<Kern3>(); // should print 'dim=3'

  return 0;
}

这给出了输出:

> dim=2
> dim=3

这正是它应该做的。但是,我无法完全理解 这是如何工作的?特别是,如果我切换

typename std::enable_if<Kern::dim == 2, bool>::type = true

行到:

typename std::enable_if<Kern::dim == 2, bool>::type = false

所以我想知道这些是什么意思?如果有人可以解释发生了什么,我将不胜感激!很遗憾,我无法找到这种在线使用 SFINAE 的精确方法。

谢谢!

最佳答案

typename std::enable_if<Kern::dim == 2, bool>::type = true>

也就是说:

typename:

以下术语定义了一个类型

std::enable_if<Kern::dim == 2, bool>

如果第一个参数中的条件为真,则此模板定义了第二个模板参数的类型。所以在这里,如果 dimm == 2 为真,模板 std::enable_if 提供了一个 bool 类型,可以通过 ::type 访问。

如果条件为真,则项:

typename std::enable_if<Kern::dim == 3, bool>::type

变得简单:

bool

现在您在其后添加 = true。您是否在任何地方使用了 bool 值?不!所以这根本不重要!你也可以写:

typename std::enable_if<Kern::dim == 3, int>::type = 42

结果是一样的,因为你没有使用你在这里定义的值!

您检查的条件在 Kern::dim == 3 中。这一个必须是真或假。

如果条件评估为 false,则模板 enable_if 不包含 type 并且表达式失败。 SFINAE 在这里发挥作用。此失败不会是错误,但会使模板定义“不可见”,因为它“不能”用作失败的原因。

评论中添加问题的插件:

当然,您可以为您的 bool 模板默认参数添加一个名称,并在下面的代码中使用它,如下所示:

template<class Kern,
         typename std::enable_if<Kern::dim == 2, bool>::type myVal = true>
inline void apply_kern(){
  std::cout << "dim=2" << "\n";
  std::cout << "bool val: " << myVal << std::endl;
}

顺便说一句: 我们经常看到在简单模板重载以相同方式工作的情况下使用 SFINAE。通常重载更容易阅读(这里可能不是:-))。我只是作为一个提示:检查是否真的需要 SFINAE 并考虑重载。

模板重载而不是 SFINAE:

/* ----------------------------------------------
   Define two kernels: characterized by their dimension
   ---------------------------------------------- */
struct Kern2 { static constexpr int dim = 2; };
struct Kern3 { static constexpr int dim = 3; };

/* ----------------------------------------------
   Choose which function to evaluate based on 
   dimension of Kern (Kern::dim)
   ---------------------------------------------- */
template < int x > inline void apply_kern_impl();

template<>
inline void apply_kern_impl<2>() { std::cout << "dim=2" << "\n"; }

template<>
inline void apply_kern_impl<3>() { std::cout << "dim=3" << "\n"; }

template< typename T>
inline void apply_kern() { apply_kern_impl<T::dim>(); }

int main()
{
    apply_kern<Kern2>(); // should print 'dim=2'
    apply_kern<Kern3>(); // should print 'dim=3'

    return 0;
}

关于c++ - SFINAE : What is happening here?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53668647/

相关文章:

c++ - 如何在数据返回一次后从类实例中删除数据

c++ - 如何正确破坏包含指针类的结构的 QVector?

c++ - 用于 smtps 的窗口 api

c++ - 将 QImage 转换为灰度

c++ - 如何将 vector <cv::Point2d> 转换为 vector <cv::Point>?

c++:获取宽字符的ascii值

c++ - 如何在不使用调试器的情况下跟踪 C++ 中的执行情况?

c++ - 具有常量和非常量值的映射

c++ - 使用 std::function 和 std::bind 时模板参数推导/替换失败

c++ - OpenGL - 为 glRotate() 找到旋转 vector