constexpr究竟有什麼用?「已登出」2018-04-23 15:44:27

主要大概幾個場景(超程式設計中用的比較多):

比如用來簡化元函式

template

constexpr bool is_same_v = std::is_same::value;

呼叫的時候可以直接

auto x = is_same_v

用於超程式設計的常成員:

template

struct is_same {

static constexpr int value = false;

}

template

struct is_same {

static constexpr int value = true;

}

這樣就可以透過

is_same::value

來呼叫這個元函式。

以及修飾常函式,

constexpr int add(int a, int b) { return a + b; }

修飾分支:

if constexpr () {}

其實你把constexpr修飾的東西看成元函式的變數就好理解了

constexpr究竟有什麼用?邱昊宇2018-04-23 19:50:17

constexpr 的主要用處有

拓寬「常量表達式」的範圍

提供顯式「要求」表示式編譯時(compile-time)求值的方法

為什麼要拓寬「常量表達式」的範圍,從原本標準庫中的很多尷尬之處就可以看出:

比如我們都知道

INT_MAX

是 C 語言的遺物,C++ 則更希望大家使用

std::numeric_limits::max()

來拿

int

型的上限。然而不幸的是,後者是個函式呼叫而不是常量,使用起來可能需要花更多效能上的心思,沒有前者那麼自由。

又比如標準檔案流,它的建構函式可以帶上這樣的第二個引數:

std

::

fstream

foo

“foo。txt”

std

::

ios

::

in

|

std

::

ios

::

out

);

這個引數是

openmode

型別的,是由實現具體定義的一種 Bitmask 型別。出於型別安全的考慮,通常用列舉值實現而不是整型。但是這樣一來就有個問題,同樣是寫

std::ios::in | std::ios::out

,如果用整型的話可以作為常量表達式使用,而為了型別安全考慮換用列舉實現(尤其是過載

|

運算子)後,就再也不可能是常量表達式了。

inline

openmode

operator

|

openmode

lhs

openmode

rhs

{

return

openmode

int_type

lhs

|

int_type

rhs

));

}

明明是這樣簡單的函式,可是對它的呼叫卻不是常量表達式。這就讓委員會陷入了必須在「型別安全」和「效率」裡二選一的尷尬境地。

標準庫裡會遇到這樣的問題,大家日常使用也會遇到。加之標準委員會很想借此機會把原本標準中對於「常量表達式」(尤其是整型常量表達式)複雜的定義重構簡化,引入 constexpr 就很合情合理了。

(此處解釋的是把「對某些簡單函式的呼叫」加入「常量表達式」定義的出發點。其它的比如 constexpr 建構函式的用途,套路是一樣的,請自行腦補。)

說到這裡,

「constexpr 函式」並不能和「編譯時求值」劃等號

,它只表達了「這個函式具備這樣的能力」。

所以才有了 constexpr 的第二個功能:「顯式『要求』表示式編譯時求值」。把它放到變數定義前,那麼用來初始化這個變數的表示式「必須」是常量表達式,否則報錯。

constexpr 函式只有同時滿足

所有引數都是常量表達式

返回的結果被用於常量表達式(比如用於初始化 constexpr 資料)

才會觸發編譯時求值。如果只有引數是常量表達式而結果不是,那麼是否觸發編譯時求值取決於具體實現。

C++17 的 constexpr if 雖然嚴格意義上不是 constexpr 而是 if 的一部分,但既然名字裡帶 constexpr,也順便提一下。

constexpr if 的主要用途是簡化模板程式碼(這也意味著除非你是庫作者或者模板狂魔,很少會用到)。很多原本需要繞彎藉助 SFINAE 或者型別 Tag 來實現,需要拆成 N 個函式的功能,可以藉助 constexpr if 寫到一個函數里。

(還有一個用途是可以代替類似

#if

的功能,但……我覺得是邪道。)

constexpr究竟有什麼用?王芊2018-04-24 08:05:22

// 判斷T是否有N個成員變數, 編譯期實現, 遞迴情形

template

struct HasParam {

constexpr operator bool () {

if constexpr (is_tuple()) {

return N == std::tuple_size::value;

} else {

return HasParam();

}

}

};

// 判斷T是否有N個成員變數, 遞迴終止情形

template

struct HasParam {

constexpr operator bool () {

return is_constructible{};

}

};

當然有用,constexpr函式可以實現編譯期的判斷, 從而更好的去做 SFINAE 型別檢查 特例化等操作。

這是一段判斷struct內有幾個成員的函式。而透過編譯期獲取類成員個數,我們就可以去做C++17的新特性structured-binding,否則在類成員數目不確定時,編譯將不能透過。

除此而外constexpr if 還以替代之前std::enable_if + type_traits的醜陋繁瑣的trick操作,大大簡化程式碼,增加程式碼的可讀性,個人建議能加就加

constexpr究竟有什麼用?海鵬2020-01-02 12:30:36

就是個高階點的【顯式】常量摺疊標記

沒什麼卵用,不知道為什麼有人非要在模板引數的位置呼叫複雜函式

constexpr最佳化?你可給我歇會吧

constexpr究竟有什麼用?MarioCanFly2020-02-19 10:56:01

今天剛好用到這個東西。是參考這篇文章做的:

CSDN-專業IT技術社群-登入

我想要給一個string做switch操作,但是c++不能對string進行switch,只能是int或enum或者class。

所以得把string轉換成int,算它的Hash值就ok了。

我想要的效果是:

switch(hash(a)){

case hash(“a”): ;

case hash(“b”): ;

}

這樣。但是hash(“a”)不屬於常量,不能case。只好把函式變成了constexpr才解決了問題。

雖然用QStringList和Qmap、Qhash都能把string轉換成int值,但我實在不想 case 0: 、case 1:不太直觀。