1

いくつかのラッパーコードをヘッダーのみのライブラリにしたいのですが。私は、ブーストライブラリに触発されて、.libの配布と、.cppのコンパイルの必要性を単純化するためだけにヘッダーを保持しました。

この例では、「zh」がラッパーであり、a.cppがリファクタリングされて、B()が独自のソースファイルに移動されています。今では動作しません。

zh

class Z
{
    public:
    void Foo(); // edited to match my code
};

Z::Foo() { } 

a.cpp

#include "z.h"
void A() { 
      Z z;
      z.Foo();
}
//void B(Z z) {
//     z.Foo();
//}

b.cpp

#include "z.h"
void B(Z z) {           
      z.Foo();
}

*エラーLNK2005: "public:__cdecl void z :: Foo()"はすでにb.objで定義されています*

zhを宣言用のzhと定義用のz.cppに分けることで、これを修正できることを私は知っています。

  • しかし、Boostライブラリは.cppファイルなしでどうやって逃げることができますか?
  • すべてがテンプレートである必要がありますか?
  • どのコードがzhに入ることができますか?
4

1 に答える 1

2

しばらくの間、このヘッダーについて考えてみましょう。

// foo.hpp

void foo(int x)
{
    /* do something */
}

(ヘッダーガードはここでは関係ありません。翻訳ユニットごとに機能します。)これで、2つの翻訳ユニットができました。

// a.cpp

#include "foo.hpp"

と:

// b.cpp

#include "foo.hpp"

foo(int x)これが最終的に行うことは、各TUに1つずつ、合計2回定義することです。単一定義規則(ODR)では、複数の定義は許可されていません。技術的には診断は必要ありませんが、コンパイラー側では簡単に行うことができるため、エラーが発生します。

inline幸いなことに、この動作を変更するキーワード、があります。

// foo.hpp

inline void foo(int x)
{
    /* do something */
}

このキーワードは、複数の定義に遭遇した場合に、単一の定義を選択して残りを破棄することが自由であることをリンカーに通知します。(これが実際に問題ないことを確認するのはあなた次第です!)この変更により、以前のODR違反が解決され、プログラムがコンパイルされます。

これで、ヘッダーを次のようにリストしました。

class Z      
{      
    public:      
    void Foo(){       
       //do stuff      
    }      
};     

これはこれと同等です:

class Z      
{      
    public:      
    void Foo();
};    

inline void Z::Foo(){       
       //do stuff      
    }

クラス内で定義されている関数は暗黙的にであるためinlineです。(これにより、エラーなしで複数の翻訳単位に定義を含めることができます。)あなたが書いたものはあなたの投稿にあるものではなく、次のようなものだと思います。

class Z      
{      
    public:      
    void Foo();
};    

void Z::Foo(){       
       //do stuff      
    }

どこinlineが欠けています。同等性が失われ、複数の定義が作成され、ODRに違反します。

解決策はinline、クラス定義内の関数を使用するか、定義によって暗黙的に使用することです。個人的には、後者の方がはるかに明確で(繰り返しを避けるため)、保守がはるかに簡単だと思います。Boostはinline、単一の定義の必要性を回避するために頻繁に使用します。

于 2012-08-15T23:15:34.870 に答える