在lpNorm<p>中,int p不是常量表达式。

3
我写了这个函数。
    template <typename T>
    double norm(const T & v, const int p) {
        return v.template lpNorm<p>();
    }

但是它不能正常工作并且出现了错误:
 error: 'p' is not a constant expression
             return v.template lpNorm<p>();
                                         ^

我认为编译器希望在编译时知道p是什么,但是我的p是动态的。

可能相关:

为什么这不是常量表达式?

非类型模板参数不是常量表达式

我该如何解决?


4
模板在编译时被解析... - Fantastic Mr Fox
3个回答

3

模板在编译时解析。因此,它们不能是运行时变量。尽管参数声明中有const,但p仍然是运行时变量。

参数声明中的const仅表示函数不能更改参数值。仍然可以使用普通非常量变量调用您的函数。


3
您无法实现这个功能。
模板是在编译时解析的。这意味着对于代码行中的lpNorm<p>() 每个

值都会生成特定于该模板的代码。如果< code>p可以是任何值,那么您需要为每个可能的值生成代码,这不是一个好主意,编译器正在告诉您这一点。 p必须在编译时已知,这意味着您需要做以下操作:

template <int p, typename T>
double norm(const T & v) {

针对您可能预期收到的任何p值进行专门化处理。

如果p确实是动态的,则需要运行时解决方案而不是编译时解决方案,因此您可能希望使用以下内容:

lpNorm(p);

显然,您需要重新定义lpNorm的工作方式。


p 设为第一个模板参数会更有意义。 - T.C.

3
你可以利用有限的p范围做到部分实现。对于lpNorm操作,通常这已经足够了。
你已经知道需要一个编译时常量作为模板参数。然而,由于p通常只在一个小范围内使用(0、1、2、inf),你可以使用以下技巧来使它适用于一小部分常用的int值。
template<typename T>
double norm(const T & v, const int p) {
  switch (p) {
  case 0:
    return v.template lpNorm<0>();
    break;
  case 1:
    return v.template lpNorm<1>();
    break;
  case 2:
    return v.template lpNorm<2>();
    break;
  case Eigen::Infinity:
    return v.template lpNorm<Eigen::Infinity>();
    break;
  default:
    break;
  }
}

出于好奇,我们能否使用一些模板魔法来生成相当于Switch的等效代码? - kloffy
更具体地说,我的意思是编写一个能够接受通用函数对象和在编译时可能出现的值的std :: integer_sequence,并生成必要的管道以根据运行时值进行选择的程序。 - kloffy
@lisyarus 没错。那将非常方便,谢谢! - kloffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接