この回答 に触発されて、このコードをコピーして貼り付けようとしました(そして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;
}
これは非常に簡単です-T
がint
として推定される場合、[a, 0.0]
のタプルを返します。 T
がdouble
と推定される場合、[0, a]
のタプルを返します。それ以外の場合は、[0, 0.0]
を返します。
ご覧のとおり、main()
関数では、foo
をconst char*
引数で呼び出しています。これにより、shouldがx
とy
が0
になります。それはではなくです。
コンパイルしようとしたときに、奇妙なエラーが発生しました。
エラー:「
{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を使用しています。
このような状況では、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部分を使用)。ブロックは_{ /*...*/ }
_です。