Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template function having its caller's context?

Tags:

c++

Consider the following code snippet.

template <T>
MyPtr<T> CreateObject()
{
    // Do something here first...

    // return our new object
    return MyPtr<T>(new T());
}

class Foo
{
private:
    Foo() { }

public:
    static MyPtr<Foo> GetNewInstance() 
    {
        // ERROR: Foo is private...
        return CreateObject<Foo>();
    }
};

class Bar
{
public:
    Bar() { }
};

int main()
{
    MyPtr<Bar> bar = CreateObject<Bar>();

    return 0;
}

Without resorting to macro for CreateObject (I like the syntax of MyPtr<type> obj = CreateObject<type>(params)), is there a way to make the function CreateObject share the same context as the caller function, thus able to access private Foo c'tor? 'friend' is not what I'm looking for as it would mean anyone calling CreateObject would have access to private Foo c'tor, which is not what I want. Overloading the new operator wouldn't work either as it is imperative that a MyPtr is returned instead of just T* (by assigning T* to MyPtr assigns a type to the object that is required somewhere else).

I guess what I'm looking for is something in between a macro and a template function (syntax of a template function but gets expanded fully like a macro). It would be quite useful to have this feature in this particular case.

like image 967
Zach Saw Avatar asked Jan 21 '26 19:01

Zach Saw


2 Answers

Well, you could do that with the passkey pattern:

template<class T, class PassKey>
MyPtr<T> CreateObject(PassKey const& key)
{
  return new T(key);
}

class FooKey{
private:
  FooKey(){} // private ctor
  FooKey(const FooKey&); // undefined private copy ctor

  friend class Foo;
};

class Foo{
public:
  // public ctor
  Foo(FooKey const&){}

  static MyPtr<Foo> GetNewInstance() 
  {
    return CreateObject<Foo>(FooKey());
  }
};

Example at Ideone.

With C++0x, this can be done much easier than creating a new Key struct every time, since template parameters are now allowed to be friends:

template<class T>
struct PassKey{
private:
  PassKey(){}
  PassKey(const PassKey<T>&);

  friend T;
};
like image 64
Xeo Avatar answered Jan 23 '26 09:01

Xeo


This is basically the same as attempting to use make_shared with a private constructor.

The only way to allow this is with friend. You're pretty much stuck in this case I'm afraid.

like image 27
Billy ONeal Avatar answered Jan 23 '26 08:01

Billy ONeal