我目前正在尝试理解 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/