C ++
相关:函数返回constexpr不编译
我觉得constexpr在C ++ 11的有用性方面有限,因为无法定义两个函数,否则它们会具有相同的签名,但一个是constexpr,另一个不是constexpr。 换句话说,如果我可以有一个constexpr std :: string构造函数,它只接受constexpr参数,而一个非constexpr std :: string构造函数用于非constexpr参数,这将非常有帮助。 另一个例子是理论上复杂的函数,可以通过使用状态来提高效率。 你不能用constexpr函数轻松做到这一点,所以你只剩下两个选择:如果你传递了非constexpr参数,或者完全放弃了constexpr(或者编写了两个单独的函数,但你可能不知道要调用哪个版本)。
因此,我的问题是:
标准兼容的C ++ 11实现是否可以允许基于constexpr参数的函数重载,还是需要更新标准? 如果不允许,是否故意不允许?
@NicolBolas:假设我有一个将enum
映射到std::string
的函数。 假设我的enum
从0
到n - 1
,最直接的方法是创建一个大小为n
的数组,填充结果。
我可以创建一个static constexpr char const * []
并在返回时构造一个std::string
(每次调用该函数时支付创建一个std::string
对象的代价),或者我可以创建一个static std::string const []
并返回我查找的值,在第一次调用函数时支付所有std::string
构造函数的代价。 看起来更好的解决方案是在编译时在内存中创建std::string
(类似于现在用char const *
所做的),但唯一的方法是提醒构造函数它有constexpr
参数。
对于除std::string
构造函数以外的示例,我认为找到一个例子非常简单,如果您可以忽略constexpr
的要求(从而创建非constexpr
函数),则可以创建更多高效的功能。 考虑这个线程:constexpr问题,为什么这两个不同的程序在g ++中运行的时间不同?
如果我用一个constexpr
参数来调用fib
,我就无法比编译器更好地完成函数调用。 但是如果我用一个非constexpr
参数来调用fib
,我可能希望让它调用我自己的版本来实现诸如memoization之类的东西(这将需要状态),所以我得到的运行时间与我通过编译的时间相似一个constexpr
论据。
基于结果是不是constexpr
,而不是参数,它必须被重载。
一个const std::string
可以存储一个指向文字的指针,知道它永远不会被写入(使用const_cast
从std::string
去除const
是必要的,这已经是未定义的行为)。 只需要存储一个布尔标志来禁止在销毁期间释放缓冲区。
但是,即使从constexpr
参数初始化,非const
字符串也需要动态分配,因为需要可写的参数副本,因此不应使用假设的constexpr
构造函数。
从标准(第7.1.6.1节[dcl.type.cv]
),修改任何创建的对象const
是未定义的行为:
除了任何声明mutable的类成员(7.1.1)可以修改以外,任何在其生命周期(3.8)修改const对象的尝试都会导致未定义的行为。
我同意这个功能缺失 - 我也需要它。 例:
double pow(double x, int n) {
// calculate x to the power of n
return ...
}
static inline double pow (double x, constexpr int n) {
// a faster implementation is possible when n is a compile time constant
return ...
}
double myfunction (double a, int b) {
double x, y;
x = pow(a, b); // call version 1 unless b becomes a compile time constant by inlining
y = pow(a, 5), // call version 2
return x + y;
}
现在我必须使用模板来做到这一点:
template <int n>
static inline double pow (double x) {
// fast implementation of x ^ n, with n a compile time constant
return ...
}
这很好,但我错过了超载的机会。 如果我为其他人使用库函数,那么根据n是否为编译时间常量,用户不得不使用不同的函数调用是不方便的,并且可能难以预测编译器是否将n减少为a编译时间常量与否。
检测和使用constexpr
不能像已经回复的其他重载一样进行,但这不是我们通常需要的。
我们有两种不同的算法,一种是constexpr
,另一种不是。 我们可以通过选择“手动”来实现正确的选择,然后用预处理宏缩短它。
通常这些重载只是通过不同的算法达到相同的结果。 在这里为了测试目的,我采用了两种算法,它们给出的答案都不相同
#include <iostream> // handy for test I/O
#include <type_traits> // handy for dealing with types
// run-time "foo" is always ultimate answer
int foo_runtime(int)
{
return 42;
}
// compile-time "foo" is factorial
constexpr int foo_compiletime(int num)
{
return num > 1 ? foo_compiletime(num - 1) * num : 1;
}
这是一个检测constexpr
的技巧。 我很确定它是由Johannes Schaub发明的,但我找不到这个引用。 非常好和清楚的把戏。
template<typename T>
constexpr typename std::remove_reference<T>::type makeprval(T && t)
{
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
所以剩下的就是编写一个“foo”来选择基于参数类型的算法并对其进行测试:
#define foo(X) (isprvalconstexpr(X)?foo_compiletime(X):foo_runtime(X))
int main(int argc, char *argv[])
{
int a = 1;
const int b = 2;
constexpr int c = 3;
const int d = argc;
std::cout << foo(a) << std::endl;
std::cout << foo(b) << std::endl;
std::cout << foo(c) << std::endl;
std::cout << foo(d) << std::endl;
}
预期的输出是:
42
2
6
42
在我尝试的少数编译器上,它的工作方式与预期相似。
链接地址: http://www.djcxy.com/p/66591.html上一篇: c++