我知道将字符串文字作为模板参数传递的唯一方法是在之前声明它:
档案a.h
#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
。溶液
答案 0 :(得分:3)
让我们从标准中为所有人的利益开始,从14.3.2模板非类型参数[temp.arg.nontype](C ++ 03标准):
1非类型非模板模板参数的模板参数 应该是以下之一:
- 积分或积分的整数常量表达式 枚举类型;或
- 非类型模板参数的名称;或
- 具有外部链接的对象或函数的地址,包括 函数模板和函数template-id但不包括非静态 班级成员,表达为&amp; id-expression 其中&amp;如果是可选的 名称是指函数或数组,或者是相应的 template-parameter是一个引用;或
- 指向成员的指针 如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副本还不支持。)字符串文字莫名其妙地仍禁止显示为模板参数。
答案 1 :(得分: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;
}