1

文字列リテラルをテンプレート引数として渡す唯一の方法は、前に宣言することです。

ファイルああ

#ifndef A_H
#define A_H

#include <string>

char EL[] = "el";


template<char* name>
struct myclass
{
  std::string get_name() { return name; }
};

typedef myclass<EL> myclass_el;

#endif

ファイルa.cpp

#include "a.cpp"

main.cpp

#include "a.h"
...

g++ -c a.cpp
g++ -c main.cpp
g++ -o main main.o a.o

そして私は得ました:

a.o:(.data+0x0): multiple definition of `EL'
main.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status

EL私は外部として宣言することはできず、 a.cpp. ソリューション?

4

2 に答える 2

3

14.3.2 テンプレート非型引数 [temp.arg.nontype] (C++03 標準) から、すべての利益のために標準が述べていることから始めましょう。

1 非型、非テンプレートのテンプレート パラメータのテンプレート引数は、次のいずれかになります。

— 整数型または列挙型の整数定数式; また

— 非型テンプレートパラメータの名前; また

—関数テンプレートと関数テンプレート ID を含むが非静的クラス メンバを除く、外部リンケージを持つオブジェクトまたは関数のアドレス。名前が関数または配列を参照する場合、& はオプションです。対応するテンプレート パラメータが参照の場合。また

— 5.3.1 で説明されているように表現されたメンバーへのポインター。

関連する部分を強調します。

さらに、パラグラフ 5 には、許可されている変換がリストされており、そのうちの 1 つは配列からポインターへの減衰です。char*パラグラフ 2 は、OP と同様の使用法を示すメモですらあります。

残っているのは、外部リンケージを使用してエラーなしでヘッダーにオブジェクトを含める方法だけです。通常の方法は、ヘッダーでの宣言と、1 つの TU での 1 つの定義のみです。

// In header
extern char EL[]; // array of unspecified size, an incomplete type
                  // extern char EL[3] is acceptable, too.

// In source
char EL[] = "el";

staticオブジェクトが外部リンケージを持っている必要があるため、可能性がないことに注意してください。TU ごとに個別のオブジェクトを持つことが意図されている場合は、名前のない名前空間が優先されます。

// In header
// NOT RECOMMENDED! Be wary of ODR-violations with such constructs
// or simply only use these in source files
namespace {

// Recommend using const here, which in turn means using extern
// change non-type template parameter accordingly
extern const char EL[] = "el";

} // namespace

興味深いことに、C++0x では、オブジェクトが外部リンケージを有効なパラメーターにするという要件が緩和されました。(GCC の私のコピーはまだそれをサポートしていません。) 文字列リテラルは、テンプレートの引数として表示することを不可解にもまだ禁止されています。

于 2011-07-24T01:26:55.337 に答える
2

修正された回答(以前の回答はナンセンスでした。申し訳ありません! また、以前の質問では、この問題はすでに完全にカバーされているはずです。)

ヘッダ:

#ifndef H_ABC
#define H_ABC

extern char EL[];

template <const char * S>
struct Foo
{
  static inline const char * get_name() { return S; }
  static const char * name;
};
template <const char * S> const char * Foo<S>::name(S);

typedef Foo<EL> MyElClass;

#endif

定義する 1 つの TU が必要ですEL

#include "header.h"
char EL[] = "EL";

テンプレートはどこでも使用できます。

#include "header.h"

char A[] = "abc";
extern const char B[] = "xyz";  // must have extern linkage!

void f() {
  std::cout << MyElClass::name << std::endl;
  std::cout << MyElClass::get_name() << std::endl;
  std::cout << Foo<A>::name << std::endl;
  std::cout << Foo<B>::name << std::endl;
}
于 2011-07-24T00:21:12.557 に答える