web-dev-qa-db-ja.com

この「未定義の外部変数」がC ++ 17でリンカーエラーにならないのはなぜですか?

C++ 17コンパイラ(Coliru)で次のプログラムをコンパイルして実行しました。プログラムでは、I 宣言済み an extern変数ですが、定義しなかった itです。ただし、コンパイラーはリンカーエラーを返しません。

#include <iostream>

extern int i; // Only declaration

int func() 
{
    if constexpr (true)
        return 0;
    else if (i)
        return i;
    else
        return -1;
}

int main() 
{
    int ret = func();
    std::cout<<"Ret : "<<ret<<std::endl;
}

なぜコンパイラはリンカエラーを出さないのですか?

38
msc

変数はODRで使用されないためです。 constexpr ifがあり、それを使用できるブランチを常に破棄します。

constexpr ifのポイントの1つは、破棄されたブランチをコンパイルする必要さえなく、整形式であることです。これは、存在しないメンバー関数への呼び出しを破棄されたブランチに配置する方法です。

58
StoryTeller

あなたの場合、変数は破棄されたステートメントでのみ使用されます。ただし、その事実を無視したとしても、C++言語仕様では、定義が欠落している場合は診断は不要であると明示的に述べられています

.2単一定義ルール

4すべてのプログラムには、破棄されたステートメント(6.4.1)の外部でそのプログラムで使用されているすべての非インライン関数または変数の定義が1つだけ含まれます。 診断は不要

言語仕様は、最適化コンパイラーが、変数のすべてのODR使用を排除するのに十分賢いかもしれないことを理解しています。その場合、潜在的なODR違反を検出して報告するように実装に要求することは、過度で不必要です。

41
AnT

コンパイラはコンパイラエラーを生成するため、linkerはリンカーエラーを生成します...

いいえ、真剣に:

if constexpr (true)

は常にtrueであるため、コンパイラーはif節の残りの部分に到達しないため無視します。したがって、iは実際には使用されません。

9
Rene

これはすでに回答されていますが、興味がある場合は、 cppreference.comconstexpr ifの正確な例を示します:

Constexpr If

if constexprで始まるステートメントは、constexpr ifステートメントと呼ばれます。

Constexpr ifステートメントでは、conditionの値は、bool型のコンテキスト変換された 定数式 でなければなりません。値がtrueの場合、statement-falseは破棄され(存在する場合)、それ以外の場合、statement-trueは破棄されます。
[...]
破棄されたステートメントは odr-use 定義されていない変数です:

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