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"

主文件

#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,但不包括非静态类成员,表示为 & id-expression ,其中 & 如果名称引用函数或数组,则 & 是可选的,或如果相应的模板参数是参考;或者

— 一个指向成员的指针,如 5.3.1 所述。

重点是我的相关部分。

此外,第 5 段列出了允许的转换,其中之一是数组到指针衰减。第 2 段甚至是一个说明,它展示了与char*OP 类似的用法。

剩下的就是如何在具有外部链接且没有错误的标头中拥有一个对象。通常的方式是在标头中声明,在一个 TU 中只有一个定义。

// 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

您需要一个 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 回答