2011-10-20 17 views
11

あなたはヘッダファイルに関数定義を配置する場合、3つの異なるソリューションがあります表示されます。inline ヘッダファイルに関数定義を置く

  • static
  • としての機能をマークして

    1. 機能をマーク関数を匿名の名前空間に入れる

    (最近まで、私は#1も気づいていませんでした)これらのソリューションとの違いは何ですか?私はどちらが好きですか?私はヘッダーのみの世界だから、ヘッダーファイルにその定義が本当に必要です。

  • +8

    あなたは忘れてしまった:それらを機能テンプレートに変えてください。それは私がいつも好むものです。 – sbi

    +1

    多くの異なるコピーと狂気につながる静的を使用しないでください。 –

    +2

    "各匿名の名前空間に1つのコピー"ソリューションは、同じ狂気につながります。 – MSalters

    答えて

    11

    で異なりますstaticと名前のない名前空間のバージョンは同じになります。各翻訳単位には独自のバージョンの関数が含まれています。つまり、静的関数fを指定すると、ポインタ&fは各翻訳単位で異なり、プログラムにはN fの異なるバージョン(バイナリでより多くのコード)。

    これは、それがN異なる(正確に等しい)の機能を提供するないヘッダ内機能を提供する適切なアプローチです。これはより明確にするために:何がしたいことはせずに、ヘッダ内の関数の定義を提供するものである場合、関数はstatic地元の人々が含まれている場合は、N異なるstaticローカル変数...

    EDITがあるだろう1つの定義ルールを破る、正しいアプローチは、関数を作ることです。inline

    +0

    「インライン」は正しいアプローチですか?あなたがそれを明示的にしたなら、それはいいでしょう。 – fredoverflow

    +0

    これについての私の理解は似ていましたが、回答と同じように投稿しましたが、削除しました。Qでちょっと立ち往生していたので、「インラインでヘッダに定義された関数をどのようにしてODRをバイパスしますか?'' $ 3.2/5セクション 'でこれに対処すると思ったが、私は確信が持てませんでした。これはおそらくQで検索されたものよりも詳細ですが、あなたはこれを黙らせてください。 –

    +0

    @Als:3.2/3 *すべてのプログラムは、そのプログラムで使用されるすべての非インライン関数またはオブジェクトの正確に1つの定義を含まなければなりません。診断は必要ありません。 [...]インライン関数は、それが使用されているすべての翻訳単位で定義されなければなりません*(C++ 03の言葉ではありますが、C++ 11では*使用*が* ODRが使用されています*) –

    0

    static機能(匿名名前空間に相当)は、各TUごとに異なるコピーを受信します。関数がリエントラントである場合、これは基本的に同一です(アセンブリレベルの違いがあるコンパイラもあります)。そうでなければ、各TUごとに異なる静的データを持ちます。インライン関数は折りたたまれています。つまり、すべてのTUに対して静的データのコピーが1つしかありません。

    +1

    @TonyK:略語を使用せず、完全な表記法を使用することに同意しますが、私は「OPは明らかに専門家ではありません」と強く反対します.OPはC++を本当に理解しているほとんどの専門家の一人ですコア。 –

    +2

    まあ、私はコメントを削除することにしましたが、遅すぎるので...ここでそれを再説明しましょう:TUのような略語を使用すると、あなたの説明を不必要にする読者の経験を想定します。 (あなたの読者がFredOverflowでない限り、明らかに、翻訳者です。 – TonyK

    4

    私の知る限り、ヘッダファイルにはinlineとテンプレート関数しか定義できません。

    static関数は非推奨であり、名前のない名前空間で定義された関数を代わりに使用する必要があります(7.3.1.1 p2を参照)。ヘッダー内の名前のない名前空間に関数を定義すると、そのヘッダーを含むすべてのソースコード(直接的または間接的)に固有の定義があります(7.3.1.1 p1を参照)。したがって、ヘッダファイルの無名の名前空間には関数を定義すべきではありません(ソースファイルのみ)。

    参照される標準は、C++ 03標準のものです。

    EDIT:関数や変数がヘッダに無名の名前空間に定義されるべきではない理由を

    次の例は示しています

    ops.hppは含まれています

    #ifndef OPS_HPP 
    #define OPS_HPP 
    namespace 
    { 
    int a; 
    } 
    #endif 
    

    DK1 .hppには、以下が含まれます。

    #ifndef DK1_HPP 
    #define DK1_HPP 
    void setValue(); 
    void printValue(); 
    #endif 
    

    dk1.cppは含まれています

    #include "dk1.hpp" 
    #include "ops.hpp" 
    #include <iostream> 
    
    void setValue() 
    { 
        a=5; 
    } 
    void printValue() 
    { 
        std::cout<<a<<std::endl; 
    } 
    

    DKを。CPPが含まれています。このような

    #include "dk1.hpp" 
    #include "ops.hpp" 
    #include <iostream> 
    
    int main() 
    { 
        // set and print a 
        setValue(); 
        printValue(); 
    
        // set and print it again 
        a = 22; 
        std::cout<<a<<std::endl; 
    
        // print it again 
        printValue(); 
    } 
    

    コンパイル:

    g++ -ansi -pedantic -Wall -Wextra dk.cpp dk1.cpp 
    

    と出力:

    5 
    22 
    5 
    

    OPS変数aは、ソースファイルdk1.cppdk.cpp

    +0

    ODRの違反ではありません。 – Flexo

    +0

    'static'関数は廃止されず、' static'オブジェクト(C++ 11以前)のみが廃止されました。 –

    +1

    @awoodland:コンパイラの観点からは本質的に間違っていることはありませんが、おそらくプログラムの観点からです。ヘッダー内の** a **のように見えるのは、実際には異なる翻訳単位の**多数の**関数で、余分なコード(より大きなバイナリ、命令キャッシュのパフォーマンス低下)を生成します。 *変数では、各翻訳単位はそれ自身のバージョンを参照します。コンパイラはそれを行い、満足します。しかし、将来それをデバッグする必要がある人は、それほど幸せではありません。 –

    関連する問題