Constexpr はコンパイルの最適化に非常に役立ちます。たとえば...
strlen(char*)
... を使用して事前コンパイルできます。
constexpr inline size_t strlen_constexpr(char* baseChar) {
return (
( baseChar[0] == 0 )
?(// if {
0
)// }
:(// else {
strlen_constexpr( baseChar+1 ) + 1
)// }
);
}
実行コストは「0」最適化すると...実行時には10倍以上遅くなる
// Test results ran on a 2010 macbook air
--------- strlen ---------
Time took for 100,000 runs:1054us.
Avg Time took for 1 run: 0.01054us.
--------- strlen_constexpr ---------
Time took for 100,000 runs:19098us.
Avg Time took for 1 run: 0.19098us.
代わりに単一の統合関数を使用できる既存のマクロ/テンプレート ハックはありますか。例:
constexpr size_t strlen_smart(char* baseChar) {
#if constexpr
... constexpr function
#else its runtime
... runtime function
}
または、次のようなオーバーロードハックも可能
constexpr size_t strlen_smart(char* baseChar) {
... constexpr function
}
inline size_t strlen_smart(char* baseChar) {
... runtime function
}
注記:この質問は、一般的な概念に適用されます。提供されているサンプル関数の代わりに、runtime と constexpr の 2 つの個別の関数を持つというものです。
免責事項:コンパイラを -O3 (最適化レベル) に設定すると、静的文字の最適化の 99.9% を修正するのに十分すぎるほどで、上記の例はすべて「無意味」になります。ただし、これは だけでなく他の「例」にも当てはまるため、この質問の要点ではありませんstrlen
。
ベストアンサー1
一般的な方法はわかりませんが、それが可能な具体的なケースを 2 つ知っています。
一部のコンパイラの特殊なケース
また、gcc と、gcc のすべての機能をコピーする clang には、組み込み関数があります__builtin_constant_p
。gcc がインライン関数への引数を定数として正しく認識するかどうかはわかりませんが、マクロから使用する必要があるのではないかと思います。
#define strlen_smart(s) \
(__builtin_constant_p(s) && __builtin_constant_p(*s) ? \
strlen_constexpr(s) : \
strlen(s))
役に立つかもしれない。静的バッファへのポインターのため、constexprとのs
両方をテストしていることに注意してください。*s
はコンパイル時の定数ですが、長さはない。
ボーナス: リテラルの特定のケース (実際の回答ではありません)
の特定のキャストについてはstrlen
、文字列リテラルがない型ですconst char *
が、 型const char[N]
は暗黙的に に変換されますconst char *
。しかし、 も に変換されますconst char (&)[N]
が、 は に変換されconst char *
ません。
したがって、次のように定義できます。
template <size_t N>
constexpr size_t strlen_smart(const char (&array)[N])
(もちろんstrlen_smart
転送もconst char *
)strlen
C++98 でも、次のような定義を持つこのタイプの引数を持つ関数を使用することがありました (関数自体をオーバーロードしようとはしませんでしたstrlen
が、オーバーロードされていたため、関数の呼び出しを回避できました)。
template <size_t N>
size_t strlen_smart(const char (&)[N]) { return N - 1; }
これには問題がある。
char buffer[10] = { 0 };
strlen_smart(buffer);
0 と表示されるはずですが、最適化されたバリアントでは 9 と表示されます。関数は、このようなバッファーで呼び出されても意味がないので、気にしませんでした。