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的函数。 假设我的enum0n - 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_caststd::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++

下一篇: get the offset of a tuple element