Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can class name be referenced implicitly at compile-time?

Is there a way to implicitly reference a class' name at compile-time?

Specifically, if I want to declare an instance of template class A using class B from within the scope of class B, is there a way to avoid explicit reference to "B" in the syntax to declare the class A instance?

To better-illustrate with an example:

// main.cpp

#include <iostream>

using namespace std;

template <typename T>
class A
{
public:
  typedef void (T::*TFunc)();

  A( T& t ) : t_( t ) {}

  void callFunc( TFunc tFunc ) { (t_.*tFunc)(); }

private:
  T& t_;
};

class LongClassName
{
public:
  LongClassName() : a_( *this ) {}

  void pubFunc()
  {
    a_.callFunc( &LongClassName::privFunc ); // Can I avoid explicitly using "LongClassName" here?
  }

private:
  void privFunc() { cout << __PRETTY_FUNCTION__ << endl; }

  A<LongClassName> a_; // Can I avoid explicitly using "LongClassName" here?
};

int main( int argc, char* argv[] )
{
  LongClassName().pubFunc();
  return 0;
}

What I've tried:
Read Is there a __CLASS__ macro in C++?, so I'm aware there's no __CLASS__ (pseudo-equivalent to __FUNCTION__) preprocessor macro. Some of the solutions to that post extract the class name from __PRETTY_FUNCTION__ - but that is a runtime solution not applicable to this situation.

I've read conflicting information on StackOverflow about whether typeid(T) is run time or compile time; either way, A<typeid(*this).name()> a_; doesn't compile, and looks wrong anyhow: there's obviously no this in that context.
By my reading, the text at https://en.cppreference.com/w/cpp/language/typeid makes clear that typeid is runtime, and so not-applicable to this situation.

like image 882
StoneThrow Avatar asked Nov 07 '19 19:11

StoneThrow


2 Answers

There is no way to avoid using the type name in LongClassName::privFunc and A<LongClassName> a_;.

That said, you can still make your life easier. You can make an alias for LongClassName that you can use it it's place. Adding

using LCN = LongClassName;

will let you use LCN in place of LongClassName

like image 72
NathanOliver Avatar answered Nov 19 '22 16:11

NathanOliver


You can declare local alias template with redefined default parameter to avoid using class name in second case:

template<typename T = LongClassName> using
A = ::A<T>;
A<> a_; // Can I avoid explicitly using "LongClassName" here?

As for shorter name for LongClassName, there is a common convention to declare corresponding type alias with a common name. It will also be helpful for writing copy / move constructors, etc:

class LongClassName
{
public:
  using Self = LongClassName;

  LongClassName() : a_( *this ) {}

  LongClassName(Self const &); // copy constructor

  Self & operator =(Self const &); // copy assignment operator

  void pubFunc()
  {
    a_.callFunc( &Self::privFunc ); // Can I avoid explicitly using "LongClassName" here?
  }

private:
  void privFunc() { cout << __PRETTY_FUNCTION__ << endl; }

  A<Self > a_; // Can I avoid explicitly using "LongClassName" here?
};
like image 25
user7860670 Avatar answered Nov 19 '22 16:11

user7860670