这里发生了什么? 我目前正在尝试理解C++代码,并且遇到了Sfaye构造(对我来说是新的)。我根据下面的代码创建了一个简单的示例: #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; }

这里发生了什么? 我目前正在尝试理解C++代码,并且遇到了Sfaye构造(对我来说是新的)。我根据下面的代码创建了一个简单的示例: #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; },c++,C++,这正是它应该做的。然而,我无法确切理解这是如何工作的?特别是,如果切换 typename std::enable_if<Kern::dim == 2, bool>::type = true typename std::enable\u如果::type=true 行至: typename std::enable_if<Kern::dim == 2, bool>::type = false typename std::enable_if::type=false 所以我

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

typename std::enable_if<Kern::dim == 2, bool>::type = true
typename std::enable\u如果::type=true
行至:

typename std::enable_if<Kern::dim == 2, bool>::type = false
typename std::enable_if::type=false
所以我想知道这些是什么意思?如果有人能解释一下发生了什么,我将不胜感激!不幸的是,我还没有找到使用SFINAE在线的精确方法

谢谢

std::enable\u如果::type
在编译时告诉编译器,如果bool表达式为true,则编译此代码。因此,当您在
main()
中调用
apply_kern()
时,编译器会输入第一个
std::enable_if
,因为您的kern::dim确实是2。例如,如果您没有调用
apply_kern()
,编译器会注意到第二个
std::enable_If
为false,并且不会编译其中的作用域。它类似于if语句,但在编译时。您还可以分别为
Kern2
Kern3
使用带有两个模板别名的模板化函数,如果您发现此语法奇怪,则会得到相同的精确结果。 对于上一个问题中的相同结果,我将尝试
typename std::enable_if::type inline void apply_kernel(){…}

typename std::enable_if<Kern::dim == 2, bool>::type = true>
以下术语定义了一个类型

std::enable_if<Kern::dim == 2, bool>
变得简单:

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

typename std::enable_if<Kern::dim == 3, int>::type = 42
顺便说一句: 我们经常看到在一些情况下使用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;
}
/*----------------------------------------------
定义两个内核:以其维度为特征
---------------------------------------------- */
结构Kern2{static constexpr int dim=2;};
结构Kern3{static constexpr int dim=3;};
/* ----------------------------------------------
选择要基于哪个函数进行求值
Kern的维数(Kern::dim)
---------------------------------------------- */
模板内联void apply_kern_impl();
模板

内联void apply_kern_impl(){std::cout通过上述修改,您的代码不应编译。
g++
clang++
都接受更改(-std=c++11/14/17)@TEDLYNMO:我错过了什么吗?
=true
=false
不是一个比较,如果省略它,它只是模板参数的默认值。SFINAE魔术是在
std::enable_if
中完成的,而不是在
=true/false
中完成的。我刚刚查阅了Eli Bendersky写的一篇很好的介绍这些天:。很好的开始。现在我们需要解释当条件为false时它是如何工作的:)@Klaus:谢谢你的逐步回答。这非常有用。我想知道,为什么我们必须为bool设置一个默认值?是否可以在函数中以某种方式访问bool::type?@Sam是的,你只需要在两者之间加一个名称
::键入
=
。但是,您不需要在函数中使用它(它仅用于SFINAE),默认值意味着用户不必编写
apply_kern();
(或
false
,这无关紧要),而只需编写
apply_kern()
。这是一个非常棒的答案。这个答案教会了我更多关于enable_if的知识,而不是我在数小时的阅读书籍和在线搜索明确的示例后所学到的知识。@LeoStar:谢谢你的回答!所以重点只是为编译提供一些将失败的表达式,除非我们在所需的情况下?是吗是吗?特别是,使用我正在查看的代码中使用的特定构造没有更深层的意义?@Sam正确。在那里选择的类型和默认值是不相关的,它们仍然未使用。整个目的是在条件未满足时不提供任何类型,从而导致替换失败(因此忽略该模板)。默认值是为了方便用户(如果删除默认值,则一切正常,用户只需在调用
apply\u kern
时向模板参数列表添加一个无意义的值)@Sam实际上,您只需要编写希望编译器编译的表达式。在其他情况下,在编译时,std::enable_if中的bool表达式将返回false,这样函数就不会被编译。我认为它就像enable_if的名称一样:编写希望得到t的所有情况编译器编译了这个。这只是一个问题或实现,但是在enable_if中使用了正确的bool表达式。如果在std::enable_if中添加一个额外的检查,就像f.e.std::is_same一样,它将获得更深刻的fir模板元编程含义
bool
typename std::enable_if<Kern::dim == 3, int>::type = 42
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;
}
/* ----------------------------------------------
   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;
}