[英]C++ 17 Metaprogramming recursive struct: enum or constexpr
为了便于说明,我展示了两个小的、略有不同的模板化递归定义。 一个使用enum
,另一个使用static constexpr
来定义一个值。
我检查了两个程序中的 output 程序集,它们完全相同,而且在语义上它们也看起来相同。
我认为constexpr
可能更现代一些,但是使用enum
/ static constexpr
之间是否存在任何差异,或者是否存在差异真正重要的任何特定用例?
// using enum
template<uint64_t N>
struct Sum {
enum : uint64_t { value = N + Sum<N - 1>::value };
};
template<>
struct Sum<0> {
enum : uint64_t { value = 1 };
};
// using static constexpr
template<uint64_t N>
struct Sum {
static constexpr uint64_t value = N + Sum<N - 1>::value;
};
template<>
struct Sum<0> {
static constexpr uint64_t value = 1;
};
提取价值:
#define sum(n) (Sum<n>::value)
最显着的区别(因为 C++17 避免了对 static 数据成员进行类外定义的需要)是枚举数与包含的 class一起实例化,而 static 数据成员仅在需要时实例化。 (但是请注意,至少 MSVC 并不总是正确地延迟它们。)
当您有多个这样的常量并且其中一些仅对某些专业化有意义时,这很重要。 在 static 数据成员案例中实例化 class 不会触发像T::maybe_exists
这样的初始化器中的错误。
另一个区别:关于ODR-used .
正如@Igor Tandetnik 所说,当您使用&Sum<0>::value
时,它仅在value
是static constexpr
变量时才有效。 那是因为, value
是枚举数的文字,而不是变量。 但请注意, &value
是ODR-used ,它要求value
在某处只有一个定义。 所以你必须声明uint64_t const Sum<0>::value;
在XXX.cpp
提供定义,在 C++17 之前( static constexpr
变量在 C++17 之后隐式是一个inline
变量,一个inline
变量在翻译单元中允许有多个定义)。
也许您认为“我根本不会使用&value
”。 但在另一种情况下你会遇到麻烦: uint64_t const& a = value
,它也是ODR-used 。 对于枚举器,其生命周期将通过引用延长(作为引用初始化)。 但是static constexpr
变量不会并且需要定义,就像使用&value
一样。 当您使用一些 function 通过引用传递时,它总是会造成一些麻烦,例如std::find
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.