C ++でのif / elseブランチのコンパイル時の削除


8

次のコードサンプルでは、ifステートメントはboolコンパイル時定数であるテンプレートパラメーターに依存しています。コンパイラはこのコードを別の方法で処理します。

  • MSVCはリンクエラーで失敗します(これは私が予想したことです)。elseブランチのテンプレート関数にはtrueテンプレートパラメーター値の特殊化がないため(呼び出されることはありません)。

  • GCCとClangはどちらも問題なくコンパイルされ、実行時の動作は正しいです。これはif、コンパイル時にステートメントを評価し、リンクする前に未使用のブランチを削除するためです。

問題は、どの動作が標準に準拠しているか(または、未定義の動作であり、どちらも独自の方法で正しいか)です。

#include <iostream>

template<const bool condition>
struct Struct
{
    void print()
    {
        if (condition)
        {
            std::cout << "True\n";
        }
        else
        {
            printIfFalse();
        }
    }

private:
    void printIfFalse();
};

template <>
void Struct<false>::printIfFalse()
{
    std::cout << "False\n";
}

int main()
{
    Struct<true> withTrue{};
    withTrue.print();

    Struct<false> withFalse{};
    withFalse.print();

    return 0;
}

4
こんにちは、あなたが探しているものではありませんが、あなたは見るかもしれませんif constexpr
Martin Morterol

1
どちらのコンパイラも正しいです。経験上、これは不特定の動作です。C ++標準では、ここで何が行われるかを指定していません。
Sam Varshavchik

@SamVarshavchikさらに一言で言え、未定義の動作(UB)です。しかし、現実の世界では、それはエラーであるか、機能します。実行時にUBはありません。
curiousguy

回答:


11

すべてのコンパイラは正しく動作します。

の呼び出しからのrequired のインスタンス化を通じてodrを使用しているためプログラムの形式が正しくなく、診断は必要ありません破棄されたステートメントの外でodr使用される関数は、プログラムで定義されている必要があります。[basic.def.odr] / 4を参照してください。それ以外の場合、プログラムの形式が正しくなく、診断は必要ありませんStruct<true>::printIfFalseStruct<true>::print()withTrue.print();

廃棄されたステートメントは、あなたが使用している場合、あなたが得るものですif constexprテンプレートで、文が選ばれた支店ではありません。したがって、プログラムを整形式にするためにできることは、if constexprではなくを使用することですif。これはC ++ 17の機能です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.