2

以下のコードでは、foo誰でもアクセスできる関数である必要がありますが、アクセスできfoo_helperないため、匿名の名前空間に配置しました。明らかに、この例ではインクルード ガードとインクルードを除外していますが、それらは存在します。

foo.h:

namespace
{
    void foo_helper() {}

    template <typename T, typename... Tail>
    void foo_helper(T head, Tail... tail)
    {
        bar(head);
        foo_helper(tail...);
    }
}

void foo();

template <typename... Args>
void foo(Args... args)
{
    before();
    foo_helper(args...);
    after();
}

foo.cpp:

void foo() {}

問題は、foo_helperの可変個引数テンプレートが機能するためには、引数のない初期バージョンが必要なことです。ただし、これにより、テンプレート以外の関数をヘッダー ファイルとして定義する必要があり、このファイルを複数のソース ファイルに含めると壊れてしまいます。の定義をfoo_helperソース ファイルに移動できません。これは、匿名の名前空間にあり、アクセス可能であることが想定されていないためです。

この問題を解決する方法はありますか?

4

2 に答える 2

3
inline void foo_helper() {};

あなたの問題を解決します。

inlineほとんどの場合、「この関数の矛盾する定義を破棄し、バージョンの 1 つを保持する」ことを意味します。

また、漠然とした方法で「インライン化」を拘束力なく示唆しています(標準ではインライン化とは何かを実際にはカバーしていません)。コンパイラは、その提案に注意を払う場合としない場合があります。

匿名の名前空間は「使用できなくする」などのことではないことに注意してください。匿名の名前空間は、リンカーの衝突をブロックするように設計されており、それだけです。andという名前の名前空間を作成しますdetails... まあ、ユーザーが中に入って突っ込まないように信頼してください。

ヘッダーで匿名の名前空間を使用することは、非常に悪い考えです。

inline匿名名前空間内のシンボルまたは関数にアクセスする関数 (またはテンプレート関数) が別のヘッダー ファイル内にある場合、ほぼ確実に ODR (1 つの定義規則) 違反が発生します。これは、同じオブジェクト、関数などに異なる 2 つの定義があり、許可されていない場所です。

例えば:

inline void bob() {
  foo(1,2,3);
}

それが#include2 つの異なる .cpp ファイルにある場合は、不正な形式のプログラムを作成しただけです (診断は不要です)。

多くの場合、そのような不適切な形式のプログラムは「期待どおりに動作」しますが、そうでない場合もあります。例として、どこかstaticで ODR 違反に依存するローカル変数を取得した場合、複数のコンパイル単位で、どれが存在し、そのプロパティが何であるかについて意見が一致しない可能性があります。

より一般的な意味では、異なる定義が「選択」されるため、プログラムのリンク順序によって動作が変わる可能性があります (非常に微妙な違いがある可能性があります)。または、月の満ち欠けでも同じことができます。

ODR 違反は、追跡が困難なローカル以外のバグに悩まされるまでは、驚くほど無害です。

于 2015-10-15T17:23:23.347 に答える