参数的重载函数(不可)在编译时推导
Overload function for arguments (not) deducable at compile time
有没有一种方法可以重载函数以区分在编译时或仅在 运行 时可评估的参数?
假设我有以下功能:
std::string lookup(int x) {
return table<x>::value;
}
这允许我在常数时间内 select 基于参数 x 的字符串值(有 space 开销)。但是,在某些情况下 x
无法在编译时提供,我需要 运行 一个 foo 版本,它以更高的时间复杂度进行查找。
我当然可以使用不同名称的函数,但我希望有一个统一的界面。
我接受了一个答案,但我仍然对完全相同的函数调用是否可以进行这种区分感兴趣。
一种选择是以类似的方式使用重载:
template <int x> std::string find() {
return table<x>::value;
}
std::string find(int x) {
return ...
}
我相信最接近的方法是在 int
和 std::integral_constant<int>
上重载 lookup
;然后,如果调用者知道 compile-type 处的值,他们可以调用后者重载:
#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>
的构造对于调用者来说不那么冗长;这是可选的。
- 重载 c 将有假阴性(例如
constexpr int
变量被传递给重载 a,而不是重载 c),但这将清除任何实际的 int 文字。
还有这招:
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);
}
这种方法在有利于但不是必需的情况下效果很好,因为整数在编译时是已知的。例如,如果它有助于优化器。但是,如果您以这种方式调用某些复杂函数的许多实例,编译时间可能会很糟糕。
有没有一种方法可以重载函数以区分在编译时或仅在 运行 时可评估的参数?
假设我有以下功能:
std::string lookup(int x) {
return table<x>::value;
}
这允许我在常数时间内 select 基于参数 x 的字符串值(有 space 开销)。但是,在某些情况下 x
无法在编译时提供,我需要 运行 一个 foo 版本,它以更高的时间复杂度进行查找。
我当然可以使用不同名称的函数,但我希望有一个统一的界面。
我接受了一个答案,但我仍然对完全相同的函数调用是否可以进行这种区分感兴趣。
一种选择是以类似的方式使用重载:
template <int x> std::string find() {
return table<x>::value;
}
std::string find(int x) {
return ...
}
我相信最接近的方法是在 int
和 std::integral_constant<int>
上重载 lookup
;然后,如果调用者知道 compile-type 处的值,他们可以调用后者重载:
#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>
的构造对于调用者来说不那么冗长;这是可选的。 - 重载 c 将有假阴性(例如
constexpr int
变量被传递给重载 a,而不是重载 c),但这将清除任何实际的 int 文字。
还有这招:
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);
}
这种方法在有利于但不是必需的情况下效果很好,因为整数在编译时是已知的。例如,如果它有助于优化器。但是,如果您以这种方式调用某些复杂函数的许多实例,编译时间可能会很糟糕。