Passing pointer to member func of outer class template to nested class
Asked Answered
I

1

1

I'm having difficulty passing a pointer to the member function Outer<T>::foo to the constructor of the nested class Outer as shown below (see also ideone).

template<typename T1>
struct Outer
{
    void foo()
    {
    }

    Outer() : inner( &Outer::foo )  // ERROR: compiles without &Outer::foo and Inner( F f ), below
    {
    }

    template<typename T2, void (T2::*F)()>
    struct Inner
    {
        Inner( F f )    // ERROR
        {
        }
    };

    Inner<Outer,&Outer::foo> inner;
};

int main()
{
    Outer<int> outer;
}

What am I doing wrong? I've begun to wonder if this is at all possible.

Inkling answered 17/12, 2014 at 22:57 Comment(7)
Aren't you referring to Outer::foo, without taking into account the expanded version. The compiler doesn't yet know what specific function pointer to grab while it is trying to instantiate the template itself!Dorsal
F is not a type, it's a function pointer. Why are you passing a parameter if you already know what the object is?Cubit
sorry, I don't see any nested classes...Overcrop
@Bot Huh? Outer<T1>::Inner is a nested template type.Kenner
still don't see any classes only structs and templatesOvercrop
@Bot The only difference between a class and a struct is default member visibility. There isn't a good reason to distinguish them in this context.Kenner
not going argue difference between struct and class. Well if it suits the context then who cares about the differences.Overcrop
A
5

The problem is that you are conflating variables and template arguments. You can use constant pointers as template arguments, or you can pass variable pointers as arguments to functions.

This works:

template<typename T1>
struct Outer
{
    void foo()
    {
    }

    Outer() : inner( &Outer::foo ) 
    {
    }

    template<typename T2>
    struct Inner
    {
        // Takes a pointer at runtime to any matching signature in T2
        Inner( void (T2::*f)( ) ) 
        {
        }
    };

    Inner<Outer> inner;
};

int main()
{
    Outer<int> outer;
}

Live

or this works:

template<typename T1>
struct Outer
{
    void foo()
    {
    }

    Outer() : inner( )  
    {
    }

    // Takes a pointer at compile time to a matching function in T2
    template<typename T2, void (T2::*f)()>
    struct Inner
    {
        Inner( )
        {
        }
    };

    Inner<Outer,&Outer::foo> inner;
};

int main()
{
    Outer<int> outer;
}

Live

Aspic answered 17/12, 2014 at 23:13 Comment(4)
Massive thanks. Here's a version of your solution ideone.com/LyYZKG . Oddly, although private, I'm able to call Outer<T>::foo() from Inner. Does the standard allow this? BTW, I tested in MSVC 2013 and GCC 4.8.3Inkling
That's legit because it is Outer that actually passes the pointer. Basically, the Outer class, who has rights to all of it's components, it choosing to pass the pointer to someone else. Outside the class it is just a pointer and public/private are not checked. If Inner tried to access Outer<T>::foo() directly it would be denied.Aspic
That's interesting Jay. Its quite similar like passing a reference to a private member outside. See my following question #27537982Inkling
A useful follow-up. Thanks.Aspic

© 2022 - 2024 — McMap. All rights reserved.