所以我在这里写了一个答案:https://stackoverflow.com/a/56569397/2642059,它努力在编译时计算log2
,如下所示:
template <unsigned int x>
constexpr enable_if_t<x != 0U, int> log2 = 1 + log2<x / 2U>;
template <>
constexpr int log2<1U> = 0;
这很好,但是我觉得我不应该专攻:
template <unsigned int x>
constexpr enable_if_t<x != 0U, int> log2 = x < 4U ? 1 : 1 + log2<x / 2U>;
代替
template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = (0u != 0u); _Tp = int]
:
prog.cpp:7:61:从constexpr std::enable_if_t<true, int> log2<4u>
递归地要求
prog.cpp:7:61:必须来自constexpr std::enable_if_t<true, int> log2<8u>
prog.cpp:10:11:从这里开始 / usr / include / c ++ / 6 / type_traits:2523:61:错误:type
中没有名为struct std::enable_if<false, int>
的类型
有没有办法防止编译器将递归展开得太远?
答案 0 :(得分:2)
您使用递归来计算log2。我们生活中的每一个递归操作都需要叶子实例。
在使用递归叶函数的情况下,可以为叶例提供非递归返回。但是,使用模板变量,提供叶子情况的唯一方法是进行专业化处理,根本没有其他方法。
我相信,使用constexpr函数而不使用TMP可以实现非常相同的目标:
#include <type_traits>
constexpr int log2(int arg) {
if (arg == 0) return 0;
if (arg == 1) return 0;
return 1 + log2(arg / 2u);
}
constexpr std::integral_constant<int, log2(16)> z; // z.value == 4
这既适用于运行时参数,也适用于编译时参数,除教育目的外,通常应优于纯TMP解决方案。
出于教育或其他未公开的目的,您可以使用排他的编译时,例如:
#include <type_traits>
template<int arg>
constexpr int log2(std::integral_constant<int, arg> ) {
static_assert(arg > 0, "Bad arg to log2!");
if constexpr (arg == 1) {
return 0;
} else {
return 1 + log2(std::integral_constant<int, arg / 2> {});
}
}
int k = log2(std::integral_constant<int, 16>{});