簡體   English   中英

Constexpr 構造函數不在編譯時求值

[英]Constexpr constructor is not evaluated at compile time

我想在編譯時引入帶有錯誤檢查的強類型。 對於我的 chrono 類型,我注意到當底層類型從int64_t更改為int32_t時,字面量會悄無聲息地變窄,從而導致溢出。 所以我引入了一個顯式檢查。

但是,即使對於無法表示的常量參數(如delay_t {10s} ,編譯時也不會檢查此檢查。

#include <chrono>
#include <cstdint>
#include <stdexcept>


struct delay_t {
    std::chrono::duration<int32_t, std::nano> value {};

    constexpr explicit delay_t(std::chrono::duration<int64_t, std::nano> delay) 
        : value {delay} 
    {
        if (value != delay) {
            throw std::runtime_error("delay cannot be represented.");
        }
    };
};

auto foo(delay_t delay) -> void {}

auto main() -> int {
    using namespace std::chrono_literals;

    foo(delay_t {10s});  // here I want a compile time error, 
                         // but I get a runtime error.

    return 0;
}

神栓

不幸的是,這會編譯並導致運行時錯誤。 我驗證了文字operator"" s是一個constexpr並且它在delay_t構造函數中使用consteval工作。 我還想使用具有運行時值的類型,所以這不是一個選項。

我如何告訴上面的編譯器在編譯時評估像time_t {10s}這樣的常量文字? 我正在使用 C++20。

constexpr僅在編譯時以常量表達式求值,不依賴於參數。

你可以將你的表達拆分為

constexpr delay_t delay{10s}; // Compile time evaluated, so error at compile time
foo(delay);

通過consteval function 傳遞它。

template<typename T>
consteval T force_constexpr(const T& value) noexcept
{
    return value;
}

你可以像這樣使用它:

foo(force_constexpr(delay_t {0s}));  // No compile-time error
foo(force_constexpr(delay_t {10s})); // Compile-time error

要在編譯時強制檢查,chrono 類型的構造需要是consteval 沒有其他辦法了。

consteval explicit delay_t(duration<int64_t, std::nano> delay)
  : delay_t {wrapped_{delay}} {};

為了也允許運行時構造,我們需要另一種構造delay_t的方法。 例如,我們可以使用static 方法,即 constexpr

constexpr static auto runtime(duration<int64_t, std::nano> delay) -> delay_t {
    return delay_t {wrapped_ {delay}};
}

由於此方法需要以某種不同的方式構造delay_ ,因此我們需要第二個非 consteval 構造函數。 但是由於我們已經有一個用於 chrono 的,我們需要引入一個私有包裝器類型

private:

struct wrapped_ {
    duration<int64_t, std::nano> value;
};

constexpr delay_t(wrapped_ delay) : value {delay.value} {
    if (value != delay.value) {
        throw std::runtime_error("delay cannot be represented.");
    }
};

使用delay_t現在默認強制執行編譯時檢查:

foo(delay_t {1s});
foo(delay_t {10s});          // gives compile time error
foo(delay_t::runtime(10s));  // gives a runtime error

godbolt 的完整示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM