【问题标题】:Using template parameters as function parameters使用模板参数作为函数参数
【发布时间】:2025-10-06 03:25:01
【问题描述】:

我可以用函数参数推断模板参数

template <typename T>
void f(T a)
{ /* */ }

f(4); // T inferred to be `int`

但是我不能使用函数参数来推断不是类型的模板参数:

template <int I>
void g(int I)  // error: declaration of 'I' shadows template parameter
{ /* */ }

假设我想编写一个函数divive_dy_2(int number),并且我想确保number 不为零。

I've seen a very simple way to do this,这将要求我将参数传递给模板参数,然后如果它为 0,它将使用 SFINAE 禁用它。

但是在 API 中公开这样的内容感觉违反直觉。有什么解决办法吗?

(是的,我可以使用异常,什么不可以,甚至可能是一个更好的主意,但我现在正在学习 SFINAE,想知道它的限制在哪里)

【问题讨论】:

  • 模板参数必须在编译时已知。直到运行时才知道参数的值(与其类型相反)。同样,SFINAE 在编译时工作。您不可能使用它来以某种方式作用于仅在运行时才知道的值。基本上,如果我有int x; cin &gt;&gt; x; g(x);,那么如果用户将来输入0,您希望这段代码现在神奇地无法编译,但如果她输入1,则编译成功。
  • However I can't use function parameters to infer template parameters, which aren't types:。好吧,你可以; for example
  • 您可以将std::integral_constant 作为参数并使用用户定义的文字来使调用更好。不过,此时您也可以使用模板参数。
  • 在您的第一个示例中,T 是从函数参数的类型推断出来的,而不是从它的值推断出来的。你不能使用函数参数的值来推断任何东西。

标签: c++ templates sfinae


【解决方案1】:

如果您的参数在编译时已知,您甚至不需要 sfinae 进行检查 - 一个简单的 assert 将提供更好的诊断。

但是,如果参数未知(这更有可能是这种情况),则您不能将其设为模板参数,并且您必须使用异常或返回错误代码来指示所提供的参数超出了支持的域。

【讨论】:

    【解决方案2】:

    把模板想成和#define 一样

    如果要使用4作为模板参数,大致是

    template <int I>
    void g()
    { ... here use I as _value_, not type}
    

    您可以快速查看 Alexandrescu 的 C++ 书籍,了解如何在模板参数中使用值。

    【讨论】:

    • 你为什么要迷惑别人?模板不是定义的东西。
    • 这有助于将它们视为编译时,as #define .