首选是这样的:
template<typename T>
bool isNotZero(const T &a)
{
if (std::is_floating_point<T>::value) return abs(a) > std::numeric_limits<T>::epsilon();
else return a;
}
或者这个:?
template<typename T>
std::enable_if<std::is_floating_point<T>::value, bool>::type
isNotZero(const T &a) { return abs(a) > std::numeric_limits<T>::epsilon(); }
template<typename T>
std::enable_if<std::is_integral<T>::value, bool>::type
isNotZero(const T &a) { return a; }
我通常使用第一种来避免许多版本的功能。
我相信是完全一样的。
第一个版本在操作码阶段优化,第二个版本在模板实例化阶段。
最佳答案
I believe it is exactly the same.
我不会说它一模一样。
在第一个版本中,您使用的条件语句在运行时评估,但是决定执行哪个分支的条件可以(并且是)在 编译时。
因此,无论输入的类型是什么,您的两个分支都必须编译并且将被编译,即使我们在编译时知道其中只有一个会被执行而另一个会死 - 我希望编译器会在这里发出警告。
在第二种情况下,您只需编译(当然是执行)适合输入类型的内容。在我看来,这使得第二种方法更胜一筹。
现在,即使在这种特殊情况下,您选择哪种方法可能没有区别,由编译时条件决定的条件执行应该通过编译时构造来表示 - SFINAE 和模板重载,而 if
应用于取决于系统运行时状态的条件。
第一种方法是不可能的,例如,如果条件的两个分支包含仅在执行相应分支时编译的代码。考虑这两种类型:
struct X
{
X(int) { }
};
struct Y
{
Y() { }
};
还有如下函数模板:
template<typename T>
T foo(const T &a)
{
if (std::is_constructible<T, int>::value)
{
return T(42);
}
else
{
return T();
}
}
现在以下调用都不合法:
foo(X()); // ERROR! X is not default-constructible
foo(Y()); // ERROR! Y is not constructible from an int
仅此一点就表明,处理编译时条件执行的适当工具通常是模板重载 + SFINAE(或可能涉及类模板特化的等效构造)。
当然,有退化案例(例如这个)允许您使用其他工具,但如果我们正在寻找概念上正确的设计指南,我相信这里有一个明显的赢家。
如果像 static if
这样的话,情况当然会有所不同。存在于 C++ 中,但目前情况并非如此 - 似乎在不久的将来也不会。
关于c++ - 'if' 带有模板参数或 SFINAE 是首选?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16178756/