C++ constexpr函数失败的模板实例化
我有一个模板类C++ constexpr函数失败的模板实例化,c++,templates,c++11,language-lawyer,constexpr,C++,Templates,C++11,Language Lawyer,Constexpr,我有一个模板类C,它有一个非类型但引用模板参数的类型p: class P { public: int x; int y; }; template <const P &x> class C { public: const int &f() { return x.x; } }; P p = {33,44}; 我还声明了一个返回对p的引用的函数: constexpr const P &h() { return p; } 然后尝试在以下方面使用这些
C
,它有一个非类型但引用模板参数的类型p
:
class P {
public:
int x;
int y;
};
template <const P &x>
class C {
public:
const int &f() { return x.x; }
};
P p = {33,44};
我还声明了一个返回对p
的引用的函数:
constexpr const P &h() { return p; }
然后尝试在以下方面使用这些:
C<p> o; // line 1
C<h()> oo; // line 2
为什么会这样?我在规范中找不到反对它的论据。我不确定这是否与中的问题完全相同,在中讨论的是嵌套实例化的实例化点。这更像是一个类型问题,但哪一个呢?我的函数h()
返回对定义良好类型(const P&
)的定义良好的变量的引用。我期望一些内联会发生,并给出正确的结果,但事实并非如此。你能告诉我为什么吗
将函数声明为内联不会改变任何问题
使用Apple LLVM版本6.0(clang-600.0.56)(基于LLVM 3.5svn
)进行了实验。我还尝试了g++-mp-4.8(MacPorts gcc48 4.8.3_2)4.8.3
,错误报告如下:
'h()' is not a valid template argument for type 'const P&' because it is not an object with external linkage
似乎我对h()
(这是一个constexpr
的调用,因此编译时可计算)不被视为这样
我忘了说,如果我们尝试使用其他类似的引用,问题是相同的:
const P &pp = p;
然后
C<pp> oo;
第二点:
error: could not convert template argument 'pp' to 'const P &'
pp
不是对象?pp
不是类型const p&
?我可以按原样使用它……我知道它是引用,但与本机引用无法区分,或者在
C<h()> oo;
coo;
§14.3.2/4引入:
[注:临时变量,未命名左值和未链接的命名左值是不可接受的模板-
对应模板参数具有引用类型时的参数
(emphasis mine)这项限制似乎受制于以下提案,仍在试图确定该提案的地位。该提案说: 指向的指针、引用和指针的语法限制 成员很笨拙,无法进行合理的重构。例如:
template<int *p> struct A {};
int n;
A<&n> a; // ok
constexpr int *p() { return &n; }
A<p()> b; // error
模板结构A{};
int n;
A;//好的
constexpr int*p(){return&n;}
A b;//错误
并进一步表示:
<> P.限制的历史原因很可能是C++
以前没有一个足够强大的
指针、引用或指向成员类型的指针的常量表达式。
然而,情况已经不是这样了。现状是
需要实现来评估这样的模板参数,但是
如果结果不为空,则必须放弃该结果
除上述内容外,对具有链接的实体的限制如下:
导出模板的工件,在
已删除对模板类型参数的链接限制
它将删除注释中有以下限制的这一部分:
未命名的左值和未链接的命名左值
全文如下:
临时值、未命名左值和未链接的命名左值是
当相应的
模板参数具有引用类型
更新
这项提案的修订版本是,我们可以在最新的工作草案中看到变化
在以下情况下,临时对象不是可接受的模板参数:
对应的模板参数具有引用类型
规范性章节为14.3.2
(临时参数非类型)段落1
,该段落与本提案一起应说明:
对于引用或指针类型的非类型模板参数
常量表达式的值不应引用(或指针)
类型,不应为以下地址:
- 子对象(1.8)
- 临时物体(12.2)
- 字符串文字(2.14.5)
- typeid表达式(5.2.8)的结果,或
- 预定义的func变量(8.4.1)
看起来这个更改实际上已经在
clanghead
中实现了,请使用-std=c++1z
标志查看您的代码工作。这意味着该更改应该是c++17的一部分,假设没有后续更改逆转或更改它。FWIW GCC 4.9.1还说错误:'h()“”不是类型“const P&”的有效模板参数,因为它不是具有外部链接的对象<代码> >代码> P<代码>代码> >代码> P> >外部链接,这与C>P><代码>有关,为什么不<代码> C>代码>?我认为问题是,自从C++中引入了CONTXPRPR以来,没有对非类型模板参数进行过检查。谢谢。我不确定文档(非常有趣!)回答我的问题。如果我理解它涉及类型等价/相等(我关心的是哪一个,但不是这个)…您可以使用clanghead
查看我更新答案中的实例,这样不仅建议被接受,而且我们还可以看到它也可以工作。标准中的注释不只是脚注或示例。有一个问题专门针对这一点。这是一个很好的发现。我在阅读本节时遗漏了未修改的左值!!!但是现在,为什么连内联函数h
都不能产生期望的结果呢?你不认为所有需要的东西都在编译器的掌控之下吗(没有陷阱)?这可能就是为什么我没有被未修改的左值所唤醒…抱歉,杰弗里,沙菲克的答案有很好的文件证明。哥伦布,当然它不是规范性的,但是有注释来澄清规范性部分,所以任何人都可以理解之前的陈述是这样说的。N4268,链接文件的修订版,在Urbana被采用。@T.C.谢谢你,自从我回答了你的问题后,我刚刚恢复了在线
C<h()> oo;
template<int *p> struct A {};
int n;
A<&n> a; // ok
constexpr int *p() { return &n; }
A<p()> b; // error