我对 SFINAE 有基本的了解,例如如何enable_if
作品。我最近遇到了this answer ,我花了一个多小时试图了解它的实际工作原理,但无济于事。
这段代码的目标是根据类中是否有特定成员来重载函数。这是复制的代码,它使用 C++11:
template <typename T> struct Model
{
vector<T> vertices;
void transform( Matrix m )
{
for(auto &&vertex : vertices)
{
vertex.pos = m * vertex.pos;
modifyNormal(vertex, m, special_());
}
}
private:
struct general_ {};
struct special_ : general_ {};
template<typename> struct int_ { typedef int type; };
template<typename Lhs, typename Rhs,
typename int_<decltype(Lhs::normal)>::type = 0>
void modifyNormal(Lhs &&lhs, Rhs &&rhs, special_) {
lhs.normal = rhs * lhs.normal;
}
template<typename Lhs, typename Rhs>
void modifyNormal(Lhs &&lhs, Rhs &&rhs, general_) {
// do nothing
}
};
对于我的生活,我无法理解这种机制是如何工作的。具体来说,typename int_<decltype(Lhs::normal)>::type = 0
是什么意思?帮助我们做到这一点,为什么我们需要在此方法中使用额外的类型 ( special_
/general_
)。
最佳答案
why do we need an extra type (
special_
/general_
) in this method
这些仅用于允许 modifyNormal
的目的函数被不同的实现重载。他们的特别是special_
使用 IS-A 关系,因为它继承自 general_
.此外,transform
函数总是调用 modifyNormal
重载需要 special_
键入,请参阅下一部分。
what does
typename int_<decltype(Lhs::normal)>::type = 0
help us do
这是一个带有默认值的模板参数。默认值存在,因此 transform
函数不必指定它,这很重要,因为另一个 modifyNormal
函数没有此模板参数。此外,添加此模板参数仅用于调用 SFINAE。
http://en.cppreference.com/w/cpp/language/sfinae
When substituting the deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error.
因此,如果发生故障,modifyNormal
函数取 special_
type 从要考虑的重载集中删除。这只剩下 modifyNormal
函数取 general_
输入并自 special_
IS-A general_
输入一切仍然有效。
如果没有发生替换失败,则 modifyNormal
使用 special_
的函数type 将被使用,因为它是更好的匹配。
注意: general_
类型是 struct
所以继承是public
默认情况下,允许 IS-A 关系而不使用 public
关键字。
编辑:
Can you comment on why we use the elaborate
typename int_<decltype(Lhs::normal)>::type
mechanism in the first place?
如上所述,这用于触发 SFINAE 行为。但是,当您将其分解时,它并不是很详尽。它的核心是要实例化 int_
的一个实例。某种类型的结构 T
它有一个 type
定义的数据类型:
int_<T>::type
由于这是在模板中使用的 typename
需要添加关键词,见When is the “typename” keyword necessary? .
typename int_<T>::type
最后,用于实例化 int_
的实际类型是什么?结构?这是由 decltype(Lhs::normal)
决定的,报告 Lhs::normal
的类型.如果输入 Lhs
类型有一个 normal
数据成员然后一切成功。但是,如果不是,则表示替换失败,这一点的重要性已在上面解释。
关于c++ - 基于类成员存在/不存在的 SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36194449/