constexpr函数失败的模板实例化 [英] template instantiation with constexpr function failure

查看:238
本文介绍了constexpr函数失败的模板实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有模板类C,该类具有非类型,但将模板参数引用为类型P:

I have template class C that has a non-type but reference template parameter to a type P:

class P {
public:
  int x;
  int y;
};

template <const P &x>
class C {
public:
  const int &f() { return x.x; }
};

我声明了类型为P的全局变量:

I declared a global variable of type P:

P p = {33,44};

我还声明了一个返回对p的引用的函数:

I also declared a function that returns a reference to p:

constexpr const P &h() { return p; }

然后尝试在以下内容中使用它们:

And then tried to use these in the following :

C<p> o;    // line 1
C<h()> oo; // line 2

当然,我对第一个实例没有问题,但第二个实例没有问题.我的编译器抱怨:

Of course I have no problem with the first instantiation but the second. My compiler complains:

error: non-type template argument does not refer to any declaration

为什么会这样?我无法在规范中找到反对它的论点.我不确定是否与在默认模板参数中调用constexpr完全相同. /a>,其中讨论的是 nested 实例化的实例化点.这里更多的是类型问题,但是哪一个呢?我的函数h()返回对定义明确的类型(const P &)定义明确的变量的引用.我希望可以进行一些内联​​,以得到正确的结果,但事实并非如此.你能告诉我为什么吗?

Why is so ? I was unable to find an argument against it in the norm. I am not sure that it is exactly the same problem as in Calling constexpr in default template argument, where the discussion was about point of instantiation of nested instanciation. Here it is more a type problem, but which one ? My function h() returns a reference to a well defined variable of the well defined type (const P &). I expected that some inlining would take place a give the right result but it is not the case. Could you tell me why ?

将函数声明为内联并不会改变问题.

Declaring the function as inline doesn't change anything to the problem.

实验用Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn完成.我也尝试使用g++-mp-4.8 (MacPorts gcc48 4.8.3_2) 4.8.3,并且错误报告为:

Experiments were done with Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn. I also tried with g++-mp-4.8 (MacPorts gcc48 4.8.3_2) 4.8.3 and the error was reported as:

'h()' is not a valid template argument for type 'const P&' because it is not an object with external linkage

好像我对h()的调用(这是一个constexpr,因此可在编译时进行计算)看起来并不像这样...

It looks like my call to h() (which is a constexpr so compile-time computable) is not seen as such...

我忘了说,如果我们尝试使用类似这样的其他引用,问题将会是相同的:

I forgot to say that the problem is the same if we try with another reference like this:

const P &pp = p;

然后

C<pp> oo;

这一次,第一个编译器说:

this time the first compiler says:

non-type template argument of reference type 'const P &' is not an object

第二个:

error: could not convert template argument 'pp' to 'const P &'

pp不是对象? pp不是const P&类型吗?好吧,我可以按原样使用它...我知道它是一个引用,但与本机引用没有区别,或者?

pp is not an object? pp is not of type const P&? Well I can use it as is it one... I know it is a reference but indistinguishable from a native reference, or ?

推荐答案

此限制似乎受到以下提议的限制

It looks like this restriction was subject to the following proposal Allow constant evaluation for all non-type template arguments, still trying to determine the status of this proposal. It says:

指针,引用和指向的指针的语法限制 成员很尴尬,无法进行合理的重构.例如:

The syntactic restrictions for pointers, references, and pointers to members are awkward and prevent reasonable refactorings. For instance:

template<int *p> struct A {};
int n;
A<&n> a; // ok

constexpr int *p() { return &n; }
A<p()> b; // error

并进一步说:

限制的历史原因很可能是C ++ 以前没有足够强的规范 指针,引用或指针到成员类型的常量表达式. 但是,情况已不再如此.现状是 需要执行以评估此类模板参数,但是 如果结果不为空,则必须丢弃该结果.

The historical reason for the restriction was most likely that C++ previously did not have a sufficiently strong specification for constant expressions of pointer, reference, or pointer-to-member type. However, that is no longer the case. The status quo is that an implementation is required to evaluate such a template argument, but must then discard the result if it turns out to not be null.

除上述内容外,对具有链接的实体的限制为 导出模板的工件,并且在删除时可能已被删除 删除了模板类型参数的链接限制.

In addition to the above, the restriction to entities with linkage is an artifact of exported templates, and could have been removed when the linkage restrictions on template type parameters were removed.

,它将在此限制下删除注释的这一部分:

and it would remove this section of the note with this restriction:

未命名的左值和没有链接的命名的左值

unnamed lvalues, and named lvalues with no linkage

整个注释如下:

临时文件,未命名的左值和没有链接的命名的左值是 模板参数不可接受时 template-parameter具有引用类型.

Temporaries, unnamed lvalues, and named lvalues with no linkage are not acceptable template-arguments when the corresponding template-parameter has reference type.

更新

此提案的修订版 N4268 通过了工作草案在Urbana 中,我们可以看到最新工作草案中的更改 N4296 .新笔记显示为:

The revised version of this proposal N4268 was adopted into the working draft at Urbana and we can see the changes in the latest working draft N4296. The new note reads:

在以下情况下,临时对象不是可接受的模板参数: 相应的模板参数具有引用类型

A temporary object is not an acceptable template-argument when the corresponding template-parameter has reference type

规范性部分是14.3.2 (temp.arg.nontype)段落 1,该提案将这样说:

The normative section is 14.3.2 (temp.arg.nontype) paragraph 1 which with this proposal would say:

对于引用或指针类型的非类型模板参数, 常量表达式的值不得引用(或用于指针) 类型,不得是)的地址:

For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • 子对象(1.8)
  • 一个临时对象(12.2)
  • 字符串文字(2.14.5)
  • typeid表达式(5.2.8)的结果,或
  • 预定义的 func 变量(8.4.1).
  • a subobject (1.8),
  • a temporary object (12.2),
  • a string literal (2.14.5),
  • the result of a typeid expression (5.2.8), or
  • a predefined func variable (8.4.1).

,我们可以在最新的标准草案 N4296 .

and we can find this new wording in the latest draft standard N4296.

该更改实际上已在clang HEAD中实施,请参见您的代码正常工作实时 ,使用-std=c++1z标志.这意味着该更改应该是C ++ 17的一部分,前提是没有随后的更改会逆转或更改它.

It looks like this change has actually been implemented in clang HEAD see your code working live, using the -std=c++1z flag. This implies the change should be part of C++17, assuming no subsequent changes reverses or alters it.

这篇关于constexpr函数失败的模板实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆