Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract outer class type from inner class instance passed to template function

I have a group of classes and inside each one is defined a nested class always with the same name.

class A {
public:
    class Common {};
    ...
};

class B {
public:
    class Common {};
    ...
};

I am trying to write a template function like this (NOT compiling code):

template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args) {
    T t(tc, args...);
    // do stuff
}

And I would like to use it as follow:

{
    ...
    A::Common ac();
    foo(ac, 42, "Hello");
    ....
}

How could I extract the outer class type from the type on the inner class instance passed to the function? Maybe with <traits>, but I am very newbie about it...

like image 387
Marco Stramezzi Avatar asked Feb 22 '18 08:02

Marco Stramezzi


People also ask

How do you access the outer class variable in an inner class?

If you want your inner class to access outer class instance variables then in the constructor for the inner class, include an argument that is a reference to the outer class instance. The outer class invokes the inner class constructor passing this as that argument.

Can inner class access outer class private variables C#?

The inner class can access any non-static member that has been declared in the outer class. Scope of a nested class is limited by the scope of its (outer) enclosing class. If nothing is specified, the nested class is private (default). Any class can be inherited into another class in C# (including a nested class).

Can inner class access outer class static variables Java?

Java inner class is associated with the object of the class and they can access all the variables and methods of the outer class. Since inner classes are associated with the instance, we can't have any static variables in them.

Can inner class access outer class private variables Python?

Bookmark this question. Show activity on this post. private This is the default, and means that the method or variable is accessible only within the Apex class in which it is defined.


1 Answers

In your following function template:

template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args);

T is in a non-deducible context. Therefore, doing:

foo(ac, 42, "Hello");

won't compile, because T can't be deduced from the function call arguments. You would need to explicitly pass A as an argument to the T template parameter:

foo<A>(ac, 42, "Hello");

However, note that T::Common will actually have to be preceded by the keyword typename, since Common is a type-dependent name:

template<typename T, typename... ARGS>
void foo(typename T::Common tc, ARGS... args);

Extracting the outer class type without giving up implicit type deduction

You could declare an outer_class_of<> class template for extracting the outer class. This template would be parameterized by the inner class type:

// primary template
template<typename>
struct outer_class_of;

Then, specialize this template for both A::Common and B:Common:

// specialization for A::Common
template<>
struct outer_class_of<A::Common> {
    using type = A; // outer class of A::Common
};

// specialization for B::Common
template<>
struct outer_class_of<B::Common> {
    using type = B; // outer class of B::Common
};

You can declare then an alias template for achieving C++14-like _t type traits:

template<typename T>
using outer_class_of_t = typename outer_class_of<T>::type;

This way, outer_class_of_t<A::Common> corresponds to A and outer_class_of_t<B::Common> to B.

Finally, you need to change your foo() function template definition to:

template<typename TCommon, typename... ARGS>
void foo(TCommon tc, ARGS... args) { 
   outer_class_of_t<TCommon> t(tc, args...);
}

When calling foo() with a A::Common or a B::Common object as function argument, TCommon will be deduced to A::Common or B::Common, respectively. outer_class_of<> is then applied on TCommon to obtain the type of the outer class.


Also, be ware of C++'s most vexing parse in:

A::Common ac();

What you want is actually:

A::Common ac{};

Otherwise, in the call to foo(), TCommon will be deduced to A::Common(*)() (i.e.: a pointer to function) instead of A::Common, since the former is declaring a function that takes no parameters and returns an A::Common object, whereas the latter is actually declaring an A::Common object.

like image 63
ネロク・ゴ Avatar answered Oct 06 '22 01:10

ネロク・ゴ