24

考虑这个示例代码:

template<class D>
char register_(){
    return D::get_dummy(); // static function
}

template<class D>
struct Foo{
    static char const dummy;
};

template<class D>
char const Foo<D>::dummy = register_<D>();

struct Bar
    : Foo<Bar>
{
    static char const get_dummy() { return 42; }
};

也在 Ideone 上。)

我希望dummy一旦有 的具体实例化就可以初始化Foo,我有Bar. 这个问题(以及最后的标准报价)解释得很清楚,为什么没有发生。

[...] 特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非静态数据成员本身的使用方式要求静态数据成员的定义存在。

有没有什么方法可以强制 dummy初始化(有效地调用register_而没有任何实例BarFoo(没有实例,所以没有构造函数诡计)并且用户Foo不需要以某种方式显式声明成员?不需要派生类做任何事情的额外 cookie。


编辑找到一种对派生类影响最小的方法:

struct Bar
    : Foo<Bar>
{   //                              vvvvvvvvvvvv
    static char const get_dummy() { (void)dummy; return 42; }
};

不过,我仍然希望派生类不必这样做。:|

4

6 回答 6

12

考虑:

template<typename T, T> struct value { };

template<typename T>
struct HasStatics {
  static int a; // we force this to be initialized
  typedef value<int&, a> value_user;
};

template<typename T>
int HasStatics<T>::a = /* whatever side-effect you want */ 0;

也可以不引入任何成员:

template<typename T, T> struct var { enum { value }; };
typedef char user;

template<typename T>
struct HasStatics {
  static int a; // we force this to be initialized
  static int b; // and this

  // hope you like the syntax!
  user :var<int&, a>::value,
       :var<int&, b>::value;
};

template<typename T>
int HasStatics<T>::a = /* whatever side-effect you want */ 0;

template<typename T>
int HasStatics<T>::b = /* whatever side-effect you want */ 0;
于 2011-06-23T14:12:16.960 回答
3

我们可以使用一个基于必须用类实例化的声明的简单技巧:

template<…&gt;
struct Auto {
  static Foo foo;
  static_assert(&foo);
};
template<…&gt; Foo Auto::foo=…;

请注意,一些编译器会警告与 null 的比较;可以使用&foo==&foo, (bool)&foo, 或((void)&foo,true)在需要时避免这种情况。

另请注意,GCC 9.0–9.2不将此视为 odr-use

于 2019-10-10T06:29:35.143 回答
0

我想到了类似的东西:

// in some c++ file (to make i with internal linkage)
static int i = init_dummy(Foo<int>::dummy);

init_dummy 的定义如下:

int init_dummy(...)
{
  return 1;
}

由于可变参数,您可以在那里进行更多初始化,例如:

static int i = init_dummy(Foo<int>::dummy, Foo<double>::dummy, Foo<whatever>::dummy);
于 2011-06-23T14:08:02.193 回答
0

我最近碰到了这个。官方解决方案将是显式模板实例化,描述为here

在上述情况下,语句应如下所示:

template class Foo::Bar;
于 2022-02-03T21:07:42.123 回答
-1

您如何检查 Bar 设置的值。我更改了您的代码并在 bar 中添加了另一个函数:

....
static char const get_dummy(int){return Foo<Bar>::dummy;}
....

它给了我完全预期的结果。我可能没有正确理解,你到底想达到什么目的?

静态成员在对象之间共享,因此必须在访问时解析它们的范围。这就是为什么我们使用 :: 通过明确告诉编译器这是我们要访问的类的成员。

于 2011-06-22T20:39:35.300 回答
-2

有没有办法在没有任何 Bar 或 Foo 实例的情况下强制 dummy 被初始化(有效地调用 register_)(没有实例,所以没有构造函数技巧)?

这还不够吗?

std::cout << Foo<int>::dummy;
于 2011-06-21T06:08:40.853 回答