web-dev-qa-db-ja.com

else-ifの後にconstexprを配置する必要がありますか?

この回答 に触発されて、このコードをコピーして貼り付けようとしました(そしてmain()にテストを追加しました):

template<typename T>
std::Tuple<int, double> foo(T a) {
    if constexpr (std::is_same_v<int, T>)
        return {a, 0.0};

    else if (std::is_same_v<double, T>)
        return {0, a};

    else
        return {0, 0.0};
}

int main()
{
    auto [x, y] = foo("");

    std::cout << x << " " << y;
}

これは非常に簡単です-Tintとして推定される場合、[a, 0.0]のタプルを返します。 Tdoubleと推定される場合、[0, a]のタプルを返します。それ以外の場合は、[0, 0.0]を返します。

ご覧のとおり、main()関数では、fooconst char*引数で呼び出しています。これにより、shouldxy0になります。それはではなくです。

コンパイルしようとしたときに、奇妙なエラーが発生しました。

エラー:「{0, a}」を「<brace-enclosed initializer list>」から「std::Tuple<int, double>」に変換できませんでした

そして、私はwhat?のようでした。なぜ私はそれを望むのか... aのタイプがdoubleとして推定される場合、std::is_sameを使用してreturn {0, a}onlyを有効にした。

だから私はすぐに cppreference if-constexprに走りました。ページの下部、Notesの上に、次のコードスニペットがあります。

extern int x; // no definition of x required
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}

思いましたoookay ..?元のコードの何が問題なのか、本当にわかりません。同じ構文とセマンティクスを使用します...

しかし、私は興味がありました。多分(当時)何かがその問題を解決するのではないかと興味があったので、元のコードを次のように変更しました。

template<typename T>
std::Tuple<int, double> foo(T a) {
    if constexpr (std::is_same_v<int, T>)
        return {a, 0.0};

    else if constexpr (std::is_same_v<double, T>) // notice the additional constexpr here
        return {0, a};

    else
        return {0, 0.0};
}

int main()
{
    auto [x, y] = foo("");

    std::cout << x << " " << y;
}

そしてほら!予想どおりにコンパイルおよび実行されたコード。だから、私の質問は-このような状況でif-elseステートメントのすべてのconstexprステートメントの後にifを置く必要がありますか?それとも単なるコンパイラですか? GCC 7.3を使用しています。

34
Fureeish

このような状況では、if-elseブロックのifステートメントごとにconstexprを配置する必要がありますか?

はい。 else-ifブロック1 嘘です:)、ブロックがある場合にのみあります1 その他のブロック1。これは、コンパイラによってコードがどのように見えるかです。

_if constexpr (std::is_same_v<int, T>)
    return {a, 0.0};
else // {
    if (std::is_same_v<double, T>)
        return {0, a};
    else
        return {0, 0.0};
// }
_

else if (/*...*/)は、誰もが使用する単なる書式設定規則です。そのため、2番目のconstexprが必要であることが明確にわかります。


1:「ブロック」は正しい用語ではありません。 ifはステートメントです(オプションのelse部分を使用)。ブロックは_{ /*...*/ }_です。

46
Rakete1111