9

基本クラス テンプレートが文字列にアクセスできるように、文字列リテラルをテンプレート パラメーターとして使用する次のコード例があります。

コードはコンパイルされますが、完全には理解できない警告が表示されます。

警告: 'ns::bar::type' にはベース 'ns::base<((const char*)(& ns::bar::name))>' があり、その型は匿名名前空間を使用します [デフォルトで有効]

以下の作業例コード:

// "test.h"
#pragma once

namespace ns 
{
    template <char const* str>
    struct base
    {
        const char *name() const { return str; }
    };

    namespace bar 
    {
        static constexpr char name[] = "bar";
        struct type : base<name> {};                // <-- this line here
    }
}

// main.cpp
#include <iostream>
#include "test.h"

int main()
{
    ns::bar::type f;
    std::cout << f.name() << std::endl;
    return 0;
}

だから私の質問は:

  1. この警告はどういう意味ですか?
  2. ここで行っている方法で、文字列リテラルをテンプレート パラメーターとして渡すことは安全ですか?

(これは gcc 4.7.2 であることに注意してください)

4

2 に答える 2

7

static constexpr char name[] = "bar";問題は、内部リンクがあるという事実に関係しています。

ヘッダーで内部リンケージが定義されているタイプは、ヘッダーを含むすべてのファイルで異なるタイプになります。

これが意図されていることはめったにないため、警告が表示されます。

これがソース ファイルで行われた場合に警告が表示されない理由は、その型が複数のファイルから参照されることは決してないためです。したがって、常にその 1 つの型になります。

于 2013-02-19T06:50:45.110 に答える
4

警告は、に含まれるname各ソースファイルに異なるアドレスがあるためtest.hです。内部リンケージ(static)があるため、各翻訳ユニットは独自のコピーを取得します。それらはリンカーによって統合されません。これは、コードが次のものと同等であることを意味します。

template<int> struct base { ... };
static constexpr int val = some_value_different_in_every_source_file;
struct type: base<val> {};

コードは提示されているとおり合法ですが、別のソースファイルに含めるtest.hと、単一定義規則に違反します。

3.21つの定義ルール[basic.def.odr]

[...]
6-クラスタイプの定義は複数存在する可能性があります[...]提供[...]:[...]

  • の各定義でD、対応する名前[...]は、オブジェクトの値(アドレスではない)が使用されている場合[...]、内部またはリンクなしのconstオブジェクトを参照できます[...]

クラス型の定義で内部リンケージを持つオブジェクトのアドレスを使用しているため、複数の変換単位でそれを使用することは未定義の動作です。

于 2013-02-19T09:04:04.777 に答える