有没有一种方法来重载一个函数,以区分参数是在编译时还是仅在运行时可评估?
假设我有下面的函数,它允许我在恒定时间内根据参数x选择一个字符串值(有空间)。
std::string lookup(int x) {
return table<x>::value;
}
它允许我在恒定时间内根据参数x选择一个字符串值(有空间开销)。然而,在某些情况下 x
不能在编译时提供,我需要运行一个时间复杂度更高的foo版本来进行查找。
当然我可以使用不同名称的函数,但我希望有一个统一的接口。
我接受了一个答案,但我还是很感兴趣,如果用完全相同的函数调用,是否可以进行这种区分?
我相信最接近的方法是重载一下 lookup
关于 int
和 std::integral_constant<int>
然后,如果调用者知道编译型的值,他们可以调用后者的重载。
#include <type_traits>
#include <string>
std::string lookup(int const& x) // a
{
return "a"; // high-complexity lookup using x
}
template<int x>
std::string lookup(std::integral_constant<int, x>) // b
{
return "b"; // return table<x>::value;
}
template<typename T = void>
void lookup(int const&&) // c
{
static_assert(
!std::is_same<T, T>{},
"to pass a compile-time constant to lookup, pass"
" an instance of std::integral_constant<int>"
);
}
template<int N>
using int_ = std::integral_constant<int, N>;
int main()
{
int x = 3;
int const y = 3;
constexpr int z = 3;
lookup(x); // calls a
lookup(y); // calls a
lookup(z); // calls a
lookup(int_<3>{}); // calls b
lookup(3); // calls c, compile-time error
}
笔记。
int_
帮忙,所以建造 std::integral_constant<int>
对调用者来说是不那么啰嗦的;这是可选的。constexpr int
变量被传递给重载a,而不是重载c),但这将剔除任何实际的int字面。一种选择是以类似的方式使用重载。
template <int x> std::string find() {
return table<x>::value;
}
std::string find(int x) {
return ...
}
也有这样的技巧。
std::string lookup(int x) {
switch(x) {
case 0: return table<0>::value;
case 1: return table<1>::value;
case 2: return table<2>::value;
case 3: return table<3>::value;
default: return generic_lookup(x);
}
当在编译时知道整数是有利的,但不是必须的时候,这种方法就会很好用。 例如,如果它有助于优化器。 但如果你以这种方式调用一些复杂函数的许多实例,它可能会成为编译时的地狱。