2013-04-25 6 views
9

次のコードをコンパイルしようとすると、リンカーエラーが発生します。Undefined symbols for architecture x86_64: "Foo()", referenced from: _main in main.o LLVM 4.2を使用しています。constexpr関数の未定義シンボル

この現象は、この機能がconstexprとマークされている場合にのみ発生します。機能がconstとマークされると、プログラムは正しくコンパイルされ、リンクされます。関数を宣言すると、リンカエラーが発生するのはなぜですか?constexpr

(私は関数を作成すると、この方法は、コンパイル時計算の利益を与えないことを認識し、関数がリンクに失敗する理由は、この時点で私は好奇心旺盛です。)

main.cppに

#include <iostream> 
#include "test.hpp" 

int main() 
{ 
    int bar = Foo(); 
    std::cout << bar << std::endl; 

    return 0; 
} 

test.hpp

constexpr int Foo(); 

constexpr関数が暗黙のうちにinlineしているためであるTEST.CPP

#include "test.hpp" 

constexpr int Foo() 
{ 
    return 42; 
} 
+0

がhttp://stackoverflow.com/questions/14391272/does-constexpr-imply-inline –

答えて

8

Why does declaring the function constexpr cause a linker error?

。段落C++ 11標準の7.1.5/2あたり:その後、パラグラフ7.1.2/4あたり

A constexpr specifier used in the declaration of a function that is not a constructor declares that function to be a constexpr function. Similarly, a constexpr specifier used in a constructor declaration declares that constructor to be a constexpr constructor. constexpr functions and constexpr constructors are implicitly inline (7.1.2).

、:

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [...]

+0

'リンケージには影響しませんinline'を参照してください。 (constとの関係を考えるとconstexprはそうだが、これを示すセクションには何もない) –

+0

@JamesKanze:編集、ありがとう –

+0

@JamesKanze:7.1.5は "The 'constexpr'指定子は、constexpr関数またはconstexprコンストラクタの型には何の効果もありません。 (言語)リンケージは関数の型(7.5)の一部です。つまり、リンケージに対する 'constexpr'の影響を制限するように見えます。 –

1

それは興味深い質問ですね。 Andy Prowlとして、constexprは の関数をinlineとしています。つまり、それを使用するすべての翻訳単位には の定義が必要です。 コンパイラからのエラーが予想されます。 (実際には、 場合、私はあなたが 機能を使用し、何の定義が存在しない場合、診断が必要とされ、正しく§3.2/ 5をお読みください。)constは異なる挙動を示す理由として

:あなたは 以外をマークすることはできません - メンバ機能constconst int Foo();と書く場合、 はconstの関数ではありませんが、戻り値の型がクラス型でない場合は を返します。ただし、 のcv修飾子は無視されるため、実際はint Foo();と同じです) 。

5

constexprの本体は、使用されるすべてのポイントで表示する必要があります。あなたの場合はtest.hppmove Foo()のコードが必要です。

は、例えば、main.cppにこのコードを検討:

constexpr int Foo(); 

int main() { 
    static_assert(Foo() == 42, "Ops"); 
} 

Foo()test.cppに定義されます。コンパイラがstatic_assertの状態を確認するには、を参照してください。main.cppが表示されない場合は、42を返します。それ無理。 constexpr関数の全体のポイントは、コンパイラがコンパイル時にそれらを「呼び出す」ことができることです。このためには、コードを参照する必要があります。

したがって、これは罰金コンパイル:

constexpr int Foo() { return 42; } 

int main() { 
    static_assert(Foo() == 42, "Ops"); 
} 
+0

+1 'static_assert'と言っていただきありがとうございます。それは私の問題の原因をはるかに明らかにします。 – Aurelius