为什么 && 在编译时严格?
Why is && strict in compile time?
我正在试验基本的模板元编程。我尝试实现结构模板,帮助我们确定它们的模板参数是否为质数。即:
template<int N, int D>
struct IsPrime_Descend {
const static bool val = (N % D != 0) && IsPrime_Descend<N, D - 1>::val;
};
template<int N>
struct IsPrime_Descend<N, 1> {
const static bool val = true;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Descend<N, N - 1>::val;
};
但是上面的实现需要线性时间。我想将其提高到 O(sqrt(n))
。当然,引入一个计算平方根的结构模板并从中降维,还有很长的路要走:
template<int N, int D>
struct Sqrt_Descend {
const static int val = D * D > N ? Sqrt_Descend<N, D - 1>::val : D;
};
template<int N>
struct Sqrt_Descend<N, 1> {
const static int val = 1;
};
template<int N>
struct Sqrt {
const static int val = Sqrt_Descend<N, N>::val;
};
template<int N, int D>
struct IsPrime_Descend {
const static bool val = (N % D != 0) && IsPrime_Descend<N, D - 1>::val;
};
template<int N>
struct IsPrime_Descend<N, 1> {
const static bool val = true;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Descend<N, Sqrt<N>::val>::val;
};
但我还尝试了其他方法:
template <int N, int D>
struct IsPrime_Ascend {
const static bool val = (N % D != 0) && (D * D <= N) && IsPrime_Ascend<N, D + 1>::val;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Ascend<N, 1>::val;
};
由于 &&
[=30 的 懒惰,我认为只要前面两个条件 ((N % D != 0) && (D * D <= N)
) 为真,此代码段就会实例化 IsPrime_Ascend<N, D>
=].但是,显然,当其中之一中断并超过模板实例化最大深度时,它不会停止。
那么,为什么 &&
在编译时是严格的(如 不是惰性 )?
Short-circuit 求值处理表达式的 求值。该表达式在 C++ 文件的文本中仍然存在,因此必须对其进行编译。如果该表达式包含模板实例化,则该模板 必须 实例化。这就是编译的工作方式(除非你使用 if constexpr
,你不能在那个上下文中使用)。
如果你想阻止进一步的实例化,你必须通过模板规则来实现,而不是表达式评估规则。因此,您需要使用模板的部分专业化,它可能使用在条件为真时处于活动状态的 SFINAE 技术。 C++20 使用 requires
子句使这更容易。
更好的是,将 IsPrime_Descend
变成 constexpr
函数。
我正在试验基本的模板元编程。我尝试实现结构模板,帮助我们确定它们的模板参数是否为质数。即:
template<int N, int D>
struct IsPrime_Descend {
const static bool val = (N % D != 0) && IsPrime_Descend<N, D - 1>::val;
};
template<int N>
struct IsPrime_Descend<N, 1> {
const static bool val = true;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Descend<N, N - 1>::val;
};
但是上面的实现需要线性时间。我想将其提高到 O(sqrt(n))
。当然,引入一个计算平方根的结构模板并从中降维,还有很长的路要走:
template<int N, int D>
struct Sqrt_Descend {
const static int val = D * D > N ? Sqrt_Descend<N, D - 1>::val : D;
};
template<int N>
struct Sqrt_Descend<N, 1> {
const static int val = 1;
};
template<int N>
struct Sqrt {
const static int val = Sqrt_Descend<N, N>::val;
};
template<int N, int D>
struct IsPrime_Descend {
const static bool val = (N % D != 0) && IsPrime_Descend<N, D - 1>::val;
};
template<int N>
struct IsPrime_Descend<N, 1> {
const static bool val = true;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Descend<N, Sqrt<N>::val>::val;
};
但我还尝试了其他方法:
template <int N, int D>
struct IsPrime_Ascend {
const static bool val = (N % D != 0) && (D * D <= N) && IsPrime_Ascend<N, D + 1>::val;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Ascend<N, 1>::val;
};
由于 &&
[=30 的 懒惰,我认为只要前面两个条件 ((N % D != 0) && (D * D <= N)
) 为真,此代码段就会实例化 IsPrime_Ascend<N, D>
=].但是,显然,当其中之一中断并超过模板实例化最大深度时,它不会停止。
那么,为什么 &&
在编译时是严格的(如 不是惰性 )?
Short-circuit 求值处理表达式的 求值。该表达式在 C++ 文件的文本中仍然存在,因此必须对其进行编译。如果该表达式包含模板实例化,则该模板 必须 实例化。这就是编译的工作方式(除非你使用 if constexpr
,你不能在那个上下文中使用)。
如果你想阻止进一步的实例化,你必须通过模板规则来实现,而不是表达式评估规则。因此,您需要使用模板的部分专业化,它可能使用在条件为真时处于活动状态的 SFINAE 技术。 C++20 使用 requires
子句使这更容易。
更好的是,将 IsPrime_Descend
变成 constexpr
函数。