简体   繁体   中英

Passing templated class with unknown type to untemplated class constructor

I have two classes, lets call them SomeClass and OtherClass.

SomeClass is templated:

template <typename T> class SomeClass
{
public:
    SomeClass (const T& value);
};

OtherClass isn't templated, but uses SomeClass.

class OtherClass
{
public:
    OtherClass (const SomeClass& c, const std::string s);
};

They are supposed to be called this way:

SomeClass<int> some(5);
OtherClass other(some, "hello, world!");

other.doSomethingWithSome();

...Obviously, this will fail to compile since the compiler needs to know SomeClass' type...

Unfortunately for me, the type of SomeClass can be pretty much anything (though the number of actual types used are limited, just unrelated), and might frequently change while in development. (I know, I know, I suppose I really could use SomeClass' type and pass it to a templated OtherClass, but its quite a tedious job since there are some many instances; also, I'd like to pretend neither class knows about the other's workings. :) )

The question is simple: how can I use this syntax? (Without having to templatize OtherClass.)

An obvious answer is that you could make SomeClass inherit from a non-template abstract class :

template <typename T>
class SomeClass : public SomeAbstractBase
{
    /* ... */
};

And in turn, OtherClass will work on SomeAbstractBase :

class OtherClass
{
public:
    OtherClass (const SomeAbstractBase& c, const std::string s);
};

You're not really giving enough to say for sure that this in an appropriate solution, but it might be. In the end, if you have no problem writing SomeAbstractBase (ie: you easily manage to identify what's common to all SomeClass<T> ), than it's probably the way to go.

You use type hiding:

class OtherClass
{
public:
  template < typename T >
  OtherClass(SomeClass<T> const& c, std::string const& s)
    : pimpl(new impl<T>(c))
    , str(s)
  {}

  void doSomething() { pimpl->doSomething(str); }

private:
  struct impl_base { virtual ~impl_base() {} virtual void doSomething(std::string) { ... }};
  template < typename T >
  struct impl : impl_base
  {
    impl(T const& )...
  };

  scoped_ptr<impl_base> pimpl;
};

You will either need to templatize OtherClass -or- specialize the OtherClass constructor to accept the types of SomeClass you need to pass.

// Otherclass can take objects of any type now
template <typename T> class OtherClass
{
public:
    OtherClass(SomeClass<T>& someclass..);
};

// or

class OtherClass
{
    // specialize the otherclass constructor
    OtherClass(SomeClass<int> someclass ..)
}

It's not clear exactly what you're trying to do. But how about a templated constructor?

class OtherClass {
public:
  template <typename T> OtherClass(const SomeClass<T>& c, const std::string& s);
  // ...
};

Of course this won't work if, for example, OtherClass needs a member of type SomeClass<T> .

Use both compile-time (templates) and runtime polymorphism (virtuals):

class MyBase {
public: 
   virtual void foo() = 0;
}


template <class T>
class SomeClass : public MyBase {
public:

   void foo () {
     // do T-specific stuff
   }
}

OtherClass then takes a MyBase* and OtherClass::doSomethingWithSome invokes it virtual foo method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM