在编译时可推导出参数的重载函数(非)。

问题描述 投票:4回答:3

有没有一种方法来重载一个函数,以区分参数是在编译时还是仅在运行时可评估?

假设我有下面的函数,它允许我在恒定时间内根据参数x选择一个字符串值(有空间)。

 std::string lookup(int x) {
     return table<x>::value;
 }

它允许我在恒定时间内根据参数x选择一个字符串值(有空间开销)。然而,在某些情况下 x 不能在编译时提供,我需要运行一个时间复杂度更高的foo版本来进行查找。

当然我可以使用不同名称的函数,但我希望有一个统一的接口。


我接受了一个答案,但我还是很感兴趣,如果用完全相同的函数调用,是否可以进行这种区分?

c++ c++11 overloading
3个回答
2
投票

我相信最接近的方法是重载一下 lookup 关于 intstd::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> 对调用者来说是不那么啰嗦的;这是可选的。
  • 重载c会有假否定值(例如 constexpr int 变量被传递给重载a,而不是重载c),但这将剔除任何实际的int字面。

2
投票

一种选择是以类似的方式使用重载。

template <int x> std::string find() {
   return table<x>::value;
}

std::string find(int x) {
    return ...
}    

0
投票

也有这样的技巧。

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);
}

当在编译时知道整数是有利的,但不是必须的时候,这种方法就会很好用。 例如,如果它有助于优化器。 但如果你以这种方式调用一些复杂函数的许多实例,它可能会成为编译时的地狱。

© www.soinside.com 2019 - 2024. All rights reserved.