1
template<typename T> struct Derived: T
{
  /*static*/ int foo(int x) { return T::foo(x) + 1; }
};

If T::foo(int x) is static then Derived<T>::foo(int x) should also be static. Otherwise Derived<T>::foo(int x) should be non-static.

Is there a way to let the compiler take care of this?

rustyx
  • 80,671
  • 25
  • 200
  • 267
devoln
  • 396
  • 4
  • 12
  • you are calling T::foo(x) directly without object. This means T::foo is absolutely static. Where is the ambiguity then? – Humam Helfawi Aug 08 '16 at 09:00
  • 1
    Aside: I'm a little skeptical of a design where this could actually be an issue. Other problems that can crop up include whether they need to use a pointer-to-function or a pointer-to-member-function to reference the ambiguous method. –  Aug 08 '16 at 09:00
  • @HumamHelfawi, *"This means T::foo is absolutely static"*. No it doesn't mean that. `T` is a base class, when someone intends to call the base class method explicitly of same name, at that time, scope resolution operator is the only way. Hence, `T::foo` can or cannot be `static`. It seems that OP wants to maintain the `static`ness for both base & derived classes. Seems like a good question. In certain scenarios it's needed. – iammilind Aug 08 '16 at 09:02
  • @iammilind, yes, it is what I want. I developing allocators that may be static or have state. Derived class is decorator for allocator that adds some features to it. But if I write it without static keyword resulting allocator loses its staticness and considered as having state. – devoln Aug 08 '16 at 09:06
  • @GLmonster I edited your question to make it clearer what you mean. Pls check if it still means what you wanted. – rustyx Aug 08 '16 at 09:07
  • @Cheers and hth. - Alf. The practical use is to use my allocators with my containers. If allocator is static then container doesn't need to hold it's pointer. So decorators must preserve staticness. – devoln Aug 08 '16 at 09:15
  • @iammilind thanks. I did not know that before. – Humam Helfawi Aug 08 '16 at 09:29
  • Why do you need to control it from the base class? If you need a *template argument* of your class to have a static method with certain signature, you can easily enforce it. – n. m. could be an AI Aug 08 '16 at 09:39

2 Answers2

1

No, you cannot propagate staticness in the sense you ask. Incidentally, you could also ask the same thing about const:

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

C++ specifiers are meant to convey intent about the interface, on which users can rely even if the implementation changes:

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

In case - through templates, for example - the implementation may vary, your interface must reflect the lowest common denominator. For const, for example, methods need to be non-const. For static, which is your question, you cannot declare static.

Note that this is not a huge imposition. Even if a method is static, you can still call it using with object semantics. So, in your case, you'll have to just use object semantics. In particular, regarding your clarification in the comments

If allocator is static then container doesn't need to hold it's pointer. So decorators must preserve staticness.

note that decorators can also not preserve staticness, because containers can hold pointers in any case, and call them via object notation, regardless of their constness.

Community
  • 1
  • 1
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • Ok. Then I will add `enum: bool {IsStateless = T::IsStateless}` to each of my decorators that could preserve staticness. I will check IsStateless in container and if it is false, I will hold a pointer to allocator. Otherwise it is not needed and I want to avoid it. I think I can achieve it with container inheritance from template specialized allocator wrapper. – devoln Aug 08 '16 at 09:43
0

Use below construct:

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");

I have tested quickly with my g++ and it works fine.

What it does

  1. Takes address of both the methods and if they are comparable then they must be static. This means that the methods signatures are expected to be same (as implied in your example).
  2. If (1) fails then check if both the foo are function pointers of their respective classes types. Here no strictness of type, but you can impose with some more meta programming. Leaving up to you.

If both of above fails, then the compiler gives an error. This static_assert can be put within class Derived.

Notes: (1) If Derived::foo is static & T::foo is not then anyways, it gives error. (2) or & and are official keywords of C++. If certain compilers like MSVC doesn't support then use || & && respectively.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    I don't need to check whether staticness is not preserved. I need to preserve it. – devoln Aug 08 '16 at 09:35
  • @GLmonster, Can you elaborate more? What do you mean by "preserve" ... "enforce" on `Derived`? Because, from your Q, it appears that either both should be `static` or both should not be `static`. With the check I demonstrated in my answer, it will give compiler error when there is any mismatch between `Derived::foo` & `T::foo`. – iammilind Aug 08 '16 at 09:36
  • if `T::foo` is `static` then `Derived::foo` should automatically become `static`. Otherwise it should automatically become non-static. In any case I don't want to get a compiler error. – devoln Aug 08 '16 at 10:01
  • @GLmonster, unless we write `static` keyword ahead of `foo()`, it won't become `static`. The same thing is true when you write `virtual` though. The compiler error is to help you to mark down, when & where the `static` keyword is missed. If the compiler errors out, that means something is wrong & need correction. – iammilind Aug 08 '16 at 10:14