c++ - 'if' 带有模板参数或 SFINAE 是首选?

标签 c++ templates c++11 sfinae

首选是这样的:

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/

相关文章:

c++ 11:战俘的简称?

C++编译器无法找到函数(与命名空间相关)

c++ - 用于 32 位字循环的 ARM 内联汇编

html - 剑道网格,数据列中的模板不起作用

c++ - 在 boost::signals2 中混合 boost 智能指针和 C++11 智能指针

c++ - 如果线程必须写在同一个 vector 上,是否可以使用线程

C++比较char数组和字符串

java - 为 Windows Mobile 6.1 选项编写应用程序?

css - 如何使内部div将外部div向下推

c++ - C++中涉及多继承和复合类的解决设计