代码保护失败并且模板来自字符串文字

发布于 2024-11-25 22:01:25 字数 690 浏览 1 评论 0原文

我知道传递字符串文字作为模板参数的唯一方法是在之前声明它:

file ah

#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

file 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。解决方案?

I know the only way to pass a string literal as template argument is to declare it before:

file 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

file 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

and I got:

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

I can't declare EL as external and I want to keep the a.cpp. Solutions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

素食主义者 2024-12-02 22:01:25

让我们从标准所说的为了所有人的利益开始,从 14.3.2 模板非类型参数 [temp.arg.nontype](C++03 标准)开始:

1 非类型、非模板模板参数的模板参数
应为以下之一:

——积分或的积分常量表达式
枚举类型;或

——非类型模板参数的名称;或

具有外部链接的对象或函数的地址,包括
函数模板和函数模板 ID,但不包括非静态
类成员,表示为 & id-表达式 其中 &是可选的,如果
名称指的是函数或数组
,或者如果相应
模板参数是一个参考;或

——指向成员表达的指针
如5.3.1所述。

强调我的相关部分。

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

剩下的就是如何在标头中包含一个具有外部链接且没有错误的对象。通常的方式是在标头中声明,并且在一个 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 副本还不支持这一点。)字符串文字仍然莫名其妙地被禁止作为模板参数出现。

Let's start with what the Standard says for the benefit of all, from 14.3.2 Template non-type arguments [temp.arg.nontype] (C++03 Standard):

1 A template-argument for a non-type, non-template template-parameter
shall be one of:

— an integral constant-expression of integral or
enumeration type; or

— the name of a non-type template-parameter; or

the address of an object or function with external linkage, including
function templates and function template-ids but excluding non-static
class members, expressed as & id-expression where the & is optional if
the name refers to a function or array
, or if the corresponding
template-parameter is a reference; or

— a pointer to member expressed
as described in 5.3.1 .

Emphasis mine for the relevant parts.

Additionally, paragraph 5 lists the conversions that are allowed and one of them is array to pointer decay. Paragraph 2 is even a note that showcases a similar use of char* as that of the OP.

All that is left is how to have an object in a header with external linkage and no errors. The usual way is a declaration in the header, and one and only one definition in one 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";

Note that static is not a possibility because of the requirement that the object have external linkage. The unnamed namespace is to be preferred if the intent is to have a separate object per 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

For the curious, C++0x relaxed the requirement that an object have external linkage to be a valid parameter. (My copy of GCC doesn't support that yet.) String literals are inexplicably still forbidden to appear as template arguments.

回忆追雨的时光 2024-12-02 22:01:25

修改后的答案(之前的答案是废话。抱歉!另外,你之前的问题应该已经完全涵盖了这个问题。)

标题:

#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;
}

Revised Answer (The previous answer was nonsense. Sorry for that! Also, your previous question should have covered this problem already entirely.)

Header:

#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

You need one TU to define EL:

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

You can use the template anywhere:

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文