0

Is it possible (without using macros) to have a template parameter deduced by a compiler in a static function that takes no parameters?

struct Widget
{
    template<typename T = ?>
    static void foo()
    {
    }
 };

 struct Base : Widget {};
 struct Derived : Base {};

 Base::foo(); // T should be deduced as Base
 Derived::foo(); // T should be deduced as Derived

In my use case, writing Base::foo<Base>(); would not only be redundant (the compiler already has that information, as I've already said Base::) but would also introduce a possibility to make a mistake - calling Base::foo<SomeOtherType>(); should be disallowed.

Is there any way to distinguish, at a compile time, whether foo is called as Base::foo() or as Derived::foo()?

rubix_addict
  • 1,811
  • 13
  • 27
  • 3
    It looka like you need CRTP here. – n. m. could be an AI Aug 11 '18 at 13:46
  • @n.m. CRTP will not solve this for deeper hierarchies. I think adding something like this to the language can solve many annoying issues, like unique_ptr not workable with covariance. I'm referring to some hypothetical mechanism that automatically infers template type (of a method or inner class) in a base class based on subclass type. – Michael Veksler Aug 11 '18 at 14:04
  • I think the key issue here is that it will be always called as `Widget::foo` – user7860670 Aug 11 '18 at 14:13
  • Some information as to what the underlying problem is could help here. CRTP seems like a very good fit, depending on what you expect `foo` to to. – super Aug 11 '18 at 14:13
  • 1
    @super Basically I want the compiler to generate one `foo` for every class in the hierarchy. My original problem is using `enable_shared_from_this` with a class hierarchy. It doesn't work well - if a base class inherits `enable_shared_from_this` then calling `shared_from_this()` inside a derived class will still return a `shared_ptr`, not `shared_ptr`, which would be more useful. I tried to present a minimal example that showcases this problem. – rubix_addict Aug 11 '18 at 14:26
  • @rubix_addict Maybe you should state in your question that the relation between `Base` and `Derived` is important to you. Because this is the part the will break when solving this with CRTP. Or directly use the `enable_shared_from_this` example because in that case it is more apparent. – TFM Aug 12 '18 at 09:07
  • One approach to a multi-level CRTP hierarchy like this is outlined in answers to [this question](https://stackoverflow.com/questions/18174441/crtp-and-multilevel-inheritance). – n. m. could be an AI Aug 12 '18 at 11:50

1 Answers1

1

One approach to a multi-level CRTP hierarchy like this is outlined in answers to this question.

Another way to do this is with injected base classes every other layer.

#include <iostream>
#include <typeinfo>

class WidgetBase
{
};

template <class D, class B = WidgetBase>
class Widget : public B
{
  public:
    static void foo()
    {
        std::cout << typeid(D).name() << " is " << sizeof(D) << " bytes large\n";
    }
};

class Base : public Widget<Base> { int a; };

class Derived : public Widget<Derived, Base> { int b; };

class MoreDerived : public Widget<MoreDerived, Derived> { };

int main()
{
    Base::foo();
    Derived::foo();
    MoreDerived::foo();
}
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243