C++11 constexpr 函数的参数在模板参数中传递
这在几周前是有效的:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
int main()
{
std::cout << func(10) << std::endl;
return 0;
}
但现在 g++ -std=c++0x
说:
main.cpp: In function ‘constexpr T func(T) [with T = int]’:
main.cpp:29:25: instantiated from here
main.cpp:24:24: error: no matching function for call to ‘tfunc()’
main.cpp:24:24: note: candidate is:
main.cpp:16:14: note: template<class T, T t> T tfunc()
main.cpp:25:1: warning: control reaches end of non-void function [-Wreturn-type]
clang++ -std=c++11
说模板的参数 tfunc
由于无效而被忽略。
这是一个错误,还是一个修复?
PS:
g++ --version
=> g++ (GCC) 4.6.2 20120120(预发布)
clang++ --version
=> clang 版本 3.0 (tags/RELEASE_30/final)
(3.0.1)
This used to work some weeks ago:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
int main()
{
std::cout << func(10) << std::endl;
return 0;
}
But now g++ -std=c++0x
says:
main.cpp: In function ‘constexpr T func(T) [with T = int]’:
main.cpp:29:25: instantiated from here
main.cpp:24:24: error: no matching function for call to ‘tfunc()’
main.cpp:24:24: note: candidate is:
main.cpp:16:14: note: template<class T, T t> T tfunc()
main.cpp:25:1: warning: control reaches end of non-void function [-Wreturn-type]
clang++ -std=c++11
says that template's parameters of tfunc<T, t>()
are ignored because invalid.
Is that a bug, or a fix ?
PS:
g++ --version
=> g++ (GCC) 4.6.2 20120120 (prerelease)
clang++ --version
=> clang version 3.0 (tags/RELEASE_30/final)
(3.0.1)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
参数
t
不是常量表达式。因此出现了错误。还需要注意的是,它不能是常量表达式。您可以将常量表达式作为参数传递,但在函数内部,保存值的对象(参数)不是常量表达式。
由于
t
不是常量表达式,因此它不能用作模板参数:也许,您想要这样的东西:
现在它应该可以工作:在线演示
The parameter
t
is not a constant expression. Hence the error. It should be also noted that it cannot be a constant expression.You can pass the constant expression as argument, but inside the function, the object (the parameter) which holds the value, is not a constant expression.
Since
t
is not a constant expression, it cannot be used as template argument:Maybe, you want something like this:
Now it should work : online demo
我感觉 constexpr 也必须在“运行时”上下文中有效,而不仅仅是在编译时有效。将函数标记为 constexpr 会鼓励编译器尝试在编译时对其求值,但该函数仍必须具有有效的运行时实现。
实际上,这意味着编译器不知道如何在运行时实现此函数:
解决方法是更改构造函数,使其将其
t
参数作为普通参数,而不是模板参数,并将构造函数标记为 constexpr:“常量表达式性质”分为三个级别:
constexpr
// 可能是常量表达式您无法真正将该列表中较低的项目转换为该列表中较高的项目列表,但显然还有其他可能的路线。
例如,对此函数的调用
不一定是常量表达式。
因此,仅当所有参数和函数的实现都可以在编译时执行时完成时,
constexpr
函数的返回值才是常量表达式。I get the feeling that
constexpr
must also be valid in a 'runtime' context, not just at compile-time. Marking a function asconstexpr
encourages the compiler to try to evaluate it at compile-time, but the function must still have a valid run-time implementation.In practice, this means that the compiler doesn't know how to implement this function at runtime:
A workaround is to change the constructor such that it takes its
t
parameter as a normal parameter, not as a template parameter, and mark the constructor asconstexpr
:There are three levels of 'constant-expression-ness':
constexpr
// Something that may be a constant-expressionYou can't really convert items that are low in that list into something that is high in that list, but obviously the other route it possible.
For example, a call to this function
isn't necessarily a constant-expression.
So the return value from a
constexpr
function is a constant expression only if all the parameters, and the implementation of the function, can be completed at executed at compile-time.回顾一下这个问题:您有两个函数,它们采用
T
类型的参数。一个将其参数作为模板参数,另一个将其作为“普通”参数。我将调用两个函数
funcT
和funcN
,而不是tfunc
和func
。您希望能够从
funcN
调用funcT
。将后者标记为 constexpr 没有帮助。任何标记为
constexpr
的函数都必须是可编译的,就好像constexpr
不存在一样。constexpr
函数有点精神分裂。它们仅在某些情况下才会升级为完整的常量表达式。不可能以简单的方式实现 funcN 在运行时运行,因为它需要能够适用于 t 的所有可能值。这将要求编译器实例化许多
tfunc
实例,每个 t 值一个实例。但是,如果您愿意使用 T 的一小部分子集,则可以解决此问题。g++ 中的模板递归限制为 1024,因此您可以使用以下代码轻松处理 T 的 1024 个值:它使用函数 < code>worker 它将递归地将“正常”参数
t
转换为模板参数u
,然后用它来实例化和执行tfunc
。关键行是
return funcT() :worker(t-1);
这有局限性。如果您想使用
long
或其他整数类型,则必须添加另一个专门化。显然,此代码仅适用于 0 到 1000 之间的 t - 确切的上限可能取决于编译器。另一种选择可能是使用某种二分搜索,对 2 的每个幂使用不同的工作函数:我认为这可以解决模板递归限制,但它仍然需要大量的实例化,并且会使如果它能工作的话,编译非常慢。
Recap the question: You have two functions which take a parameter of type
T
. One takes its parameter as a template parameter, and the other as a 'normal' parameter.I'm going to call the two functions
funcT
andfuncN
instead oftfunc
andfunc
.You wish to be able to call
funcT
fromfuncN
. Marking the latter as aconstexpr
doesn't help.Any function marked as
constexpr
must be compilable as if theconstexpr
wasn't there.constexpr
functions are a little schizophrenic. They only graduate to full constant-expressions in certain circumstances.It would not be possible to implement funcN to run at runtime in a simple way, as it would need to be able to work for all possible values of t. This would require the compiler to instantiate many instances of
tfunc
, one for each value of t. But you can work around this if you're willing to live with a small subset of T. There is a template-recursion limit of 1024 in g++, so you can easily handle 1024 values of T with this code:It uses a function
worker
which will recursively convert the 'normal' parametert
into a template parameteru
, which it then uses to instantiate and executetfunc<T,u>
.The crucial line is
return funcT<T,u>() : worker<T, u+1>(t-1);
This has limitations. If you want to use
long
, or other integral types, you'll have to add another specialization. Obviously, this code only works for t between 0 and 1000 - the exact upper limit is probably compiler-dependent. Another option might be to use a binary search of sorts, with a different worker function for each power of 2:I think this will work around the template-recursion-limit, but it will still require a very large number of instantiations and would make compilation very slow, if it works at all.
看起来它应该给出一个错误 - 它无法知道您将一个常量值作为 t 传递给了 func。
更一般地说,您不能使用运行时值作为模板参数。模板本质上是一个编译时构造。
Looks like it should give an error - it has no way of knowing that you passed in a constant value as t to func.
More generally, you can't use runtime values as template arguments. Templates are inherently a compile-time construct.