【问题标题】:Propagate method staticness to derived class将方法静态性传播到派生类
【发布时间】:2016-08-08 08:54:44
【问题描述】:
template<typename T> struct Derived: T
{
  /*static*/ int foo(int x) { return T::foo(x) + 1; }
};

如果T::foo(int x)static,那么Derived&lt;T&gt;::foo(int x) 也应该是static。否则Derived&lt;T&gt;::foo(int x) 应该是非静态的。

有没有办法让编译器处理这个问题?

【问题讨论】:

  • 您正在直接调用 T::foo(x) 而没有对象。这意味着 T::foo 是绝对静态的。那么歧义在哪里呢?
  • 旁白:我对这实际上可能成为问题的设计有点怀疑。其他可能出现的问题包括他们是否需要使用指向函数的指针或指向成员函数的指针来引用不明确的方法。
  • @HumamHelfawi, “这意味着 T::foo 是绝对静态的”。不,不是那个意思。 T 是一个基类,当有人打算显式调用同名的基类方法时,此时范围解析运算符是唯一的方法。因此,T::foo 可以或不能是static。 OP 似乎希望为基类和派生类维护staticness。似乎是个好问题。在某些情况下需要它。
  • @iammilind,是的,这就是我想要的。我开发可能是静态的或有状态的分配器。派生类是分配器的装饰器,为其添加了一些功能。但是,如果我在没有 static 关键字的情况下编写它,则分配器会失去其静态性并被视为具有状态。
  • @GLmonster 我编辑了您的问题,以使您的意思更清楚。请检查它是否仍然意味着您想要的。

标签: c++ c++11


【解决方案1】:

不,您不能按照您的要求传播staticness。顺便说一句,你也可以对const提出同样的问题:

int foo(int x) { return bar(x) + 1; } // Infer that foo is const because bar is

C++ 说明符旨在传达关于接口的意图,即使实现发生变化,用户也可以依赖它:

static int foo(x); // This method does not require an object
int foo(x) const; // This method will not modify the object

如果 - 例如通过模板 - 实现可能会有所不同,您的界面必须反映最低公分母。例如const,方法必须是非const。对于static,这是你的问题,你不能声明static

请注意,这不是一个巨大的强制。即使一个方法是static,你也可以still call it using with object semantics。因此,在您的情况下,您必须只使用对象语义。特别是关于您在 cmets 中的澄清

如果分配器是静态的,那么容器不需要保存它的指针。所以装饰器必须保持静态。

请注意,装饰器也可以保留staticness,因为容器可以在任何情况下都保存指针,并通过对象表示法调用它们,而不管它们的@987654332 @ness。

【讨论】:

  • 好的。然后我会将enum: bool {IsStateless = T::IsStateless} 添加到我的每个可以保持静态的装饰器中。我将检查容器中的 IsStateless,如果它为假,我将持有一个指向分配器的指针。否则不需要它,我想避免它。我想我可以通过模板专用分配器包装器的容器继承来实现它。
【解决方案2】:

使用以下构造:

static_assert(std::is_same<decltype(&Derived::foo), decltype(&T::foo)>::value or
              (std::is_member_function_pointer<decltype(&Derived::foo)>::value and 
               std::is_member_function_pointer<decltype(&T::foo)>::value), 
              "Derived::foo & T::foo are not having same static-ness");

我已经用我的 g++ 进行了快速测试,效果很好。

它的作用

  1. 获取这两种方法的地址,如果它们具有可比性,则 他们必须是static。这意味着方法签名是 预期相同(如您的示例中所暗示的那样)。
  2. 如果 (1) 失败,则检查 foo 是否都是 它们各自的类类型。这里没有严格的类型,但你可以强加一些更多的元编程。交给你了。

如果以上两个都失败,那么编译器会报错。这个static_assert可以放在class Derived里面。

注意事项:(1) 如果Derived::foostaticT::foo 不是那么无论如何,它会给出错误。 (2)or&and是C++的官方关键字。如果某些编译器(如 MSVC)不支持,则分别使用 ||&amp;&amp;

【讨论】:

  • 我不需要检查是否没有保留静态性。我需要保存它。
  • @GLmonster,你能详细说明一下吗? Derived 上的“保留”...“强制”是什么意思?因为,从您的 Q 看来,两者都应该是static,或者两者都不应该是static。通过我在回答中演示的检查,当Derived::fooT::foo 之间存在任何不匹配时,它会给出编译器错误。
  • 如果T::foostatic 那么Derived&lt;T&gt;::foo 应该自动变成static。否则它应该自动变成非静态的。无论如何,我不想得到编译器错误。
  • @GLmonster,除非我们在foo() 之前写static 关键字,否则它不会变成static。但是,当您编写 virtual 时,情况也是如此。编译器错误是为了帮助您标记丢失static 关键字的时间和位置。如果编译器出错,这意味着有问题需要更正。
猜你喜欢
  • 2012-05-24
  • 2013-01-10
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
  • 2014-07-31
  • 2010-10-10
  • 2012-06-25
  • 1970-01-01
相关资源
最近更新 更多