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";具有内部联系的事实。

在标头中定义了内部链接的任何类型在包含标头的每个文件中都是不同的类型。

这很少是意图 - 因此是警告。

在源文件中执行此操作时没有警告的原因是因为该类型不能被多个文件引用 - 因此它将始终是一种类型。

于 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.2 一个定义规则[basic.def.odr]

[...]
6 - 可以有多个类类型的定义 [...] 提供 [...]:[...]

  • in each definition of D, corresponding names [...] can refer to a const object with internal or no linkage [only] if [...] the value (but not the address) of the object is used [...]

You're using the address of an object with internal linkage in the definition of a class type, so using it in more than one translation unit is undefined behaviour.

于 2013-02-19T09:04:04.777 回答