Constexpr 与模板元编程 - 性能差异

Constexpr vs Template Metaprogramming - performance differences

我可以看到 constexpr 正在赢得越来越多的领域,其使用模板元编程 (TMP) 的理由之一是性能。我的问题是:

  1. 有这方面性能对比的例子吗?

  2. 如果 TMP 更好,为什么不用 constexpr 替换它呢?

TMP 保证它是 运行 编译时,但这也可以用 constexpr 来完成。 Constexpr 处理浮点数,而 TMP 不处理浮点数,对于我见过的所有示例,替换 TMP 的 constexpr 函数更容易阅读和使用更少的代码行。 constexpr 还允许条件和循环,而 TMP 仅处理循环的递归 "simulations"。

我之前在这里 () 询问过一个相关问题 - 我有 3 种不同的元编程方式 - 这里首选 constexpr 函数方式..

constexpr 函数通常更具可读性,因为它们是常规函数。

注意它可以在运行时使用,即使有编译时常量参数(在调用站点)。

constexpr int f(int n) { /*...*/ }

constexpr int f5 = f(5); // Compile time.
int f4 = f(4); // Runtime time (compiler can optimize as for non-constexpr functions though)

对于运行时性能,在常量表达式中使用时也有类似的情况,因为都是在编译时完成的。

对于编译时性能,TMP 的问题是实例化的数量,而 constexpr 函数(带有常规参数)通常使用较少的实例化,因此 TMP 通常使编译时间更长。

但是,如果需要记忆(对于递归实现的斐波那契数列)

constexpr std::size_t fibonacci(std::size_t n)
{
    if (n < 2) return 1;
    return fibonacci(n - 1) + fibonacci(n - 2);
}
template <std::size_t N> struct Fibonacci
{
    constexpr std::size_t value = Fibonacci<N - 2>::value + Fibonacci<N - 1>::value;
};
template <> struct Fibonacci<0>
{
    constexpr std::size_t value = 1;
};
template <> struct Fibonacci<1>
{
    constexpr std::size_t value = 1;
};

TMP 应该重用实例化,而 constexpr 函数可能每次都重新计算它。在那种情况下,TMP 将编译得更快。

And why not replace TMP with constexpr if it is better?

首先,我们不会放弃使用的 TMP,以实现追溯兼容性。

那么TMP一般更适应return种或者几种。

template <typename T> struct add_pointer
{
    using type = T*;
};

using int_ptr = add_pointer<int>::type;

而 constexpr 需要 decltype and/or std::declval

template <typename T> struct Tag { using type = T; };
constexpr Tag<T*> add_pointer(Tag<T>) {return {}; }

using int_ptr = decltype(add_pointer(Tag<int>{})::type;