繁体   English   中英

静态模板成员变量具有内部链接但未定义

[英]static template member variable has internal linkage but is not defined

是的,我知道,有一个几乎相同标题的问题,但它指的是一个不同的情况(给出相同的clang错误信息)。 在我的例子中,我有一个带有大匿名命名空间的.cpp文件(包含实现细节)。 在该命名空间中是一个具有静态数据成员的traits类模板,我需要从匿名命名空间外部访问该模板。 让我充实一点:

file.hpp

namespace bar {
  template<typename A>
  struct foo
  {
    static_assert(is_same<A,float>::value || is_same<A,double>::value, "");
    static void set_static_var(A const&x);
    // ...
  };
}

file.cpp

namespace {
  template<typename A>
  struct foo_traits
  {
    // lots of static code supporting the implementation of bar::foo<>
    static A datum;
  };
  template<> float  foo_traits<float>::datum;   // no change if this is in global namespace
  template<> double foo_traits<double>::datum;
  template struct foo_traits<float>;
  template struct foo_traits<double>;
}

namespace bar {
  template<typename A>
  void foo<A>::set_static_var(A const&x)
  {
    foo_traits<A>::datum = x;
  }
  template struct foo<double>;     // error only appears if these lines are present.
  template struct foo<float>;      // but without these lines, the whole file is void.
}

我在变量foo_traits<>::datum (后来的链接失败)上得到了上述错误。 在编辑中添加的注意事项我使用了clang++ -std=c++11 -stdlib=libc++ (版本3.3), 它只产生一个警告,但是(正如我所说)在我的实际应用程序中警告由链接失败备份(确切地说,所述符号缺失)。 但是,gcc没有编译器警告。 也许这是一个铿锵的bug? 结束说明

定义这些变量的正确方法是什么? 请注意,在anonymouns命名空间之外声明它们将无法编译。 还要注意,AFAIK,与普通非模板相同的构造才起作用。

注意我不是在问如何规避这个问题(我能想到自己),但是如何正确地完成这个问题。

我认为正确的解决方案很简单:

namespace {
  template<typename A>
  struct foo_traits
  {
    // lots of static code supporting the implementation of bar::foo<>
    static A datum;
  };
  template<typename A> A foo_traits<A>::datum;
}

你的代码AFAICT的问题在于

float foo_traits<float>::datum;

指的是不存在的foo_traits (代码中的template<>也是不允许的,Clang也会给出错误)。

看到这个实例

问题是静态数据成员的显式特化声明只有在包含初始化程序时才是定义,否则就是声明。 C ++ 11 14.7.3 / 13:

如果声明包含初始化器,则模板的静态数据成员的显式特化是定义; 否则,这是一个声明。 [注意:需要默认初始化的模板的静态数据成员的定义必须使用braced-init-list

 template<> X Q<int>::x; // declaration template<> X Q<int>::x (); // error: declares a function template<> X Q<int>::x { }; // definition 

- 尾注]

如果为专业化提供初始值设定项,Clang会正确编译程序

template<> float  foo_traits<float>::datum = 0;
template<> double foo_traits<double>::datum = 0;

我错误地认为原始程序是正确的,显然gcc错误地将声明视为定义,即使它们缺少初始化程序

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM