如何判断参数何时来自硬编码数字?

How to tell when an argument is from a hardcoded number?

我希望能够判断传递给函数、方法或 class 方法的数字参数是否来自硬编码数字。

例如打电话

MyFunc(2);

int a = 1;
MyFunc(a);

应该重载函数以允许不同的实现或某种区分方式

void MyFunc(int num)
{
  if (isHardcodedNumber(num))
    doThis();
  else
    doThat();
}

这是简化版。理想情况下,我需要一个采用模板参数并适用于任何内置数字类型的解决方案。

这可能吗?

你分不清这两种情况。

您的函数只是获取传递给它的堆栈上(或寄存器中,取决于您的处理器)的值。

无法知道该值在被压入堆栈或复制到寄存器之前来自哪里(除非,当然,你传递了一个额外的参数来表示如此)。

你可以有点通过重载右值引用来做到这一点,尽管这会阻止你拥有值版本(因为它变得模棱两可):

#include <iostream>
using namespace std;

void f(int&& f)
{
    std::cout << "r-value reference: " << f << '\n';
}

void f(const int& f)
{
    std::cout << "value: " << f << '\n';
}

// you can't have void f(int) as it is now ambiguous.

int main()
{
    f(1);

    int a = 2;

    f(a);

    // it can be fooled though
    f(std::move(a));

    return 0;
}

打印:

r-value reference: 1
value: 2
r-value reference: 2

看这里:http://ideone.com/gZoD3m

实际上,我可以想出一个极其丑陋的 hack 来实现它。但请不要.. 这仅供学术讨论。

bool isNumber(const char* x){
  return isdigit(x[0]);
}

#define MyFunc_t(x) MyFunc(x,#x)

void MyFunc(int x , const char* xStr){
  bool isHardcodedNumber = isNumber(xStr);
  //do...
}

MyFunc_t(4);
int x = 8;
MyFunc_t(x);

模板专家也许可以将其转换为编译时常量,但我不会走那么远。

但无论如何,请不要放在第一位。

好吧,正如其他人所说 - 不建议这样做,只是为了表明它在某种程度上是可能的,但我不确定它是否适用于所有情况:

首先,您应该知道 - 您可以测试函数是否在 constexpr 上下文中被调用。只需检查其 noexcept 属性 - 如 here.

所述

所以,你可以测试:

constexpr int f_constexpr(int a)
{
   return a;
}

int main(int argc, char* argv[])
{
   cout << noexcept(f_constexpr(7)) << endl; // print 1
   cout << noexcept(f_constexpr(argc)) << endl; // print 0
}

你得到 1,然后从上面的这个程序中得到 0

不幸的是,在 f_constexpr(int) 正文中你总是得到 false - 因为参数 a 不被视为常量。所以,似乎是错误的方式。

但是..

您可以使用模板标签分派和宏 - 来实现某些功能:

template <bool isConstexpr>
struct f_impl;

template <>
struct f_impl<false>
{
    static int f(int a)
    {
        cout << "well, I'm not constexpr f()\n";
        return a;
    }
};

constexpr int f_constexpr(int a)
{
    return a;
}

template <>
struct f_impl<true>
{
    static constexpr int f(int a)
    {
        return f_constexpr(a);
    }
};

和宏定义 - 可以肯定 - 你总是有相同的参数:

#define f(a) f_impl<noexcept(f_constexpr(a))>::f(a)

因此,只需检查它是否有效:

int main(int argc, char* argv[]) {
    constexpr int a = f(7);
    cout << "constexpr was called..." << endl; 
    int c = f(argc);
    cout << "non constexpr was called, I guess..." << endl; 
    cout << a << endl;
    cout << c << endl;

}

live demo并输出:

constexpr was called...

well, I'm not constexpr f()

non constexpr was called, I guess...

7

1