I would like to get the templated type of the base class inside of an object that owns an instance of the derived class. The code snippet below won't work because Base and its ArbitraryType can't be referenced through DerivedString. (line marked with the exclamation point). However, it can most definitely be inferred from the type of its own template (OneOfTheDerivedTypes). In my case, I intend for AnotherObject with a defined template to be inherited from, so I don't want to just hardcode the return type to GetSomethingFromThingy().
// -------------------
// Provided by my API:
// -------------------
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
};
template <typename OneOfTheDerivedTypes>
class AnotherObject<OneOfTheDerivedTypes> {
// Other functions that perform useful tasks are here so that
// classes that inherit from AnotherObject need not implement them.
void SomethingMagical();
// A function with a specific return type.
virtual DerivedString::Base::ArbitraryType GetSomethingFromThingy() = 0; /* ! */
protected:
OneOfTheDerivedTypes thingy;
};
// --------------------------------------
// Someone using my API would make these:
// --------------------------------------
class DerivedFloat : public Base<float> {
void DoSomething(float) override;
};
class DerivedString : public Base<string> {
void DoSomething(string) override;
};
class UsefulObject : public AnotherObject<DerivedString> {
// Knows the required return type of GetSomethingFromThingy() without
// needing to specify it as a template. Should throw compile-time error
// if you tried to override with a different return type. In other words,
// forces return type to be string because of use of DerivedString.
string GetSomethingFromThingy() override;
};
One solution to this is specify an additional template arg called ArbitraryType as seen below:
template <typename OneOfTheDerivedTypes, typename ArbitraryType>
class AnotherObject<OneOfTheDerivedTypes> {
virtual ArbitraryType GetSomethingFromThingy() = 0;
protected:
OneOfTheDerivedTypes thingy;
};
class UsefulObject<DerivedString, string> : public AnotherObject<DerivedString, string> {
string GetSomethingFromThingy() override;
};
The programmer then must specify both parameters where OneOfTheDerivedTypes is either DerivedFloat or DerivedString and ArbitraryType is float or string, respectively. Not a good solution because ArbitraryType is completely specified by the choice of OneOfTheDerivedTypes.
I think the extra template (ArbitraryType in AnotherObject) could be avoided by having Base return an instance of ArbitraryType in a public function (call it ReturnInstanceOfArbitraryType()) and use decltype(OneOfTheDerivedTypes::ReturnInstanceOfArbitraryType()) inside of AnotherObject. This seems inelegant because ReturnInstanceOfArbitraryType() is not useful otherwise (and must be public). Is this a case where the proper thing to do is to use a traits class? Is there a better solution? (Still getting the hang of some of this new C++11 stuff). Thanks!