相关疑难解决方法(0)

什么时候constexpr函数在编译时得到评估?

由于在运行时可能会调用声明为constexpr的函数,编译器在哪个条件下决定是在编译时还是在运行时计算它?

template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
    return (expo != 0 )? base * POW(base, expo -1) : 1;
}

int main(int argc, char** argv)
{
    int i = 0;
    std::cin >> i;

    std::cout << POW(i, 2) << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我在编译时是未知的,这可能是编译器将POW()视为在运行时调用的常规函数​​的原因.然而,这种动态虽然看起来很方便,但却具有一些不切实际的含义.例如,是否有一种情况我希望编译器在编译时计算constexpr函数,编译器决定将其视为普通函数,而它在编译时也会工作?有任何已知的常见陷阱吗?

c++ runtime compile-time constexpr c++11

58
推荐指数
2
解决办法
1万
查看次数

constexpr重载

相关:函数返回constexpr无法编译

我觉得constexpr在C++ 11中的用处有限,因为无法定义两个本来具有相同签名的函数,但有一个是constexpr而另一个不是constexpr.换句话说,如果我有一个constexpr std :: string构造函数只接受constexpr参数,并且非constexpr std :: string构造函数用于非constexpr参数,那将非常有用.另一个例子是理论上复杂的功能,通过使用状态可以提高效率.使用constexpr函数你不能轻易做到这一点,所以你有两个选择:如果你传入非constexpr参数,那么constexpr函数非常慢,或者完全放弃constexpr(或写两个单独的函数,但你可能不知道要调用哪个版本).

因此,我的问题是:

是否有可能符合标准的C++ 11实现允许基于constexpr参数的函数重载,或者这需要更新标准?如果不允许,是否故意不允许?


@NicolBolas:假设我有一个映射enum到a 的函数std::string.最直接的方式做到这一点,假设我enum去从0n - 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 ++在不同的时间内运行?

如果我fib用一个constexpr参数调用,我不能比编译器完全优化掉函数调用做得更好.但是,如果我fib使用非constexpr参数调用,我可能希望让它调用我自己的版本来实现memoization(这将需要状态)之类的东西,所以我得到的运行时间类似于我通过constexpr参数时的编译时间.

c++ overloading compile-time-constant constexpr c++11

45
推荐指数
5
解决办法
8601
查看次数

用SFINAE检测constexpr

我正在努力升级一些C++代码以利用C++ 11中的新功能.我有一个特性类,其中有一些函数返回基本类型,这些函数大部分时间(但并不总是)返回一个常量表达式.我想根据功能是否做不同的事情constexpr.我提出了以下方法:

template<typename Trait>
struct test
{
    template<int Value = Trait::f()>
    static std::true_type do_call(int){ return std::true_type(); }

    static std::false_type do_call(...){ return std::false_type(); }

    static bool call(){ return do_call(0); }
};

struct trait
{
    static int f(){ return 15; }
};

struct ctrait
{
    static constexpr int f(){ return 20; }
};

int main()
{
   std::cout << "regular: " << test<trait>::call() << std::endl;
   std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

额外的int/ ...参数是这样的,如果两个函数在SFINAE之后可用,则第一个函数通过重载分辨率来选择. …

c++ templates sfinae constexpr c++11

35
推荐指数
1
解决办法
3983
查看次数

检测宏中的整数常量表达式

Linux内核邮件列表中讨论了一个宏,该宏测试其参数是否为整数常量表达式,并且本身是一个整数常量表达式.

Martin Uecker提出的一种不使用内置函数的特别聪明的方法(从glibc的tgmath.h中获取灵感)是:

#define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))
Run Code Online (Sandbox Code Playgroud)

1如果参数是整数常量表达式,0则此宏扩展为值的整数常量表达式,否则.但是,它依赖于sizeof(void)允许(和不同于sizeof(int)),这是一个GNU C扩展.

是否可以在没有内置函数的情况下编写这样的宏而不依赖于语言扩展?如果是,它会评估其论点吗?


有关上面显示的宏的解释,请参阅:Linux Kernel的__is_constexpr宏

c macros linux-kernel language-lawyer

35
推荐指数
2
解决办法
8290
查看次数

constexpr是否暗示noexcept?

constexpr说明noexcept符是否意味着函数的说明符?对类似问题的回答说明者说"是" inline,但Eric Niebler的文章让我想知道对当前问题的可能答案.在我看来,答案取决于使用constexpr函数的上下文:是常量表达式上下文还是运行时上下文,即在编译时是否已知函数的所有参数.

我希望答案是"是",但简单的检查表明情况并非如此.

constexpr
bool f(int) noexcept
{
    return true;
}

constexpr
bool g(int)
{
    return true;
}

static_assert(noexcept(f(1)));
static_assert(noexcept(g(2))); // comment this line to check runtime behaviour

#include <cassert>
#include <cstdlib>

int
main(int argc, char * [])
{
    assert(noexcept(f(argc)));
    assert(noexcept(g(argc)));
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

c++ inline noexcept constexpr c++14

33
推荐指数
2
解决办法
3006
查看次数

什么是consteval?

显然,consteval它将成为C++ 20中的关键字.它的cppreference页面目前是空白的.它会是什么以及它与它有什么关系constexpr

c++ c++20 consteval

30
推荐指数
1
解决办法
2895
查看次数

C ++检查语句是否可以评估为constexpr

有没有一种方法可以确定是否可以对constexpr求值,并将结果用作constexpr布尔值?我的简化用例如下:

template <typename base>
class derived
{
    template<size_t size>
    void do_stuff() { (...) }

    void do_stuff(size_t size) { (...) }
public:
    void execute()
    {
        if constexpr(is_constexpr(base::get_data())
        {
            do_stuff<base::get_data()>();
        }
        else
        {
            do_stuff(base::get_data());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的目标是C ++ 2a。

我发现了以下reddit线程,但我不是宏的忠实拥护者。https://www.reddit.com/r/cpp/comments/7c208c/is_constexpr_a_macro_that_check_if_an_expression/

c++ template-meta-programming constexpr c++20 if-constexpr

23
推荐指数
3
解决办法
1291
查看次数

有可能知道constexpr什么时候真的是constexpr?

由于constexpr的扩展版本(我想从C++ 14开始),你可以声明constexpr函数,它们可以用作"真正的"constexpr,即代码在编译时执行或者可以表现为内联函数.那么什么时候可以有这个程序:

#include <iostream>

constexpr int foo(const int s) {
  return s + 4;
}

int main()
{
    std::cout << foo(3) << std::endl;
    const int bar = 3;
    std::cout << foo(bar) << std::endl;
    constexpr int a = 3;
    std::cout << foo(a) << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当然,结果是:

7
7
7
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.所以我的问题是:如果函数在编译时或运行时执行,有没有办法(可能是标准的)知道foo(const int s)?

编辑:也可以在运行时知道在编译时是否评估了函数?

c++ constexpr c++14 c++17

21
推荐指数
5
解决办法
2800
查看次数

constexpr,static_assert和inlining

我之前根据参数是否constexpr询问函数重载.我正试图解决这个问题的令人失望的答案,以建立一个更聪明的断言功能.这大致是我想做的事情:

inline void smart_assert (bool condition) {
    if (is_constexpr (condition))
        static_assert (condition, "Error!!!");
    else
        assert (condition);
}
Run Code Online (Sandbox Code Playgroud)

基本上,我们的想法是编译时检查总是比运行时检查更好,如果可以在编译时检查.但是,由于内联和常量折叠之类的东西,我不能总是知道是否可以进行编译时间检查.这意味着可能存在assert (condition)编译的情况,assert(false)代码只是等待我运行它并在我发现错误之前执行该路径.

因此,如果有某种方法来检查条件是否是constexpr(由于内联或其他优化),我可以static_assert在可能的情况下调用,否则返回运行时断言.幸运的是,gcc具有内在函数__builtin_constant_p (exp),如果exp是constexpr 则返回true .我不知道其他编译器是否有这种内在的,但我希望这可以解决我的问题.这是我提出的代码:

#include <cassert>
#undef IS_CONSTEXPR

#if defined __GNUC__
    #define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
    #define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers

inline void smart_assert (bool const condition) { 
    static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
    if (!IS_CONSTEXPR(condition))
        assert (condition);
}

#undef IS_CONSTEXPR
Run Code Online (Sandbox Code Playgroud)

static_assert …

c++ inline static-assert constexpr c++11

13
推荐指数
2
解决办法
4713
查看次数

尽可能在编译时执行函数契约

(这个问题的灵感来自于如何生成编译错误以防止某些VALUE(非类型)进入函数?)

比方说,我们有一个单一的参数foo,语义定义为

int foo(int arg) {
    int* parg;
    if (arg != 5) {
        parg = &arg;
    }

    return *parg;
}
Run Code Online (Sandbox Code Playgroud)

上面的整个代码用于说明一个简单的想法 - 函数返回它自己的参数,除非参数等于5,在这种情况下行为是未定义的.

现在,挑战 - 以这种方式修改函数,如果它的参数在编译时已知,则应生成编译器诊断(警告或错误),如果不是,则在运行时仍未定义行为.解决方案可能依赖于编译器,只要它可以在四大编译器中的任何一个中使用.

以下是一些无法解决问题的潜在路线:

  • 使函数成为一个模板,将其参数作为模板参数 - 这不能解决问题,因为它使函数不适合运行时参数
  • 使函数成为一个constexpr- 这不能解决问题,因为即使编译器看到未定义的行为,它们也不会在我的测试中产生诊断 - 相反,gcc会插入ud2指令,这不是我想要的.

c++

13
推荐指数
1
解决办法
388
查看次数