Я хотел бы получить шаблонный тип базового класса внутри объекта, которому принадлежит экземпляр производного класса. Приведенный ниже фрагмент кода не будет работать, поскольку на Base и его ArbitraryType нельзя ссылаться через DerivedString. (строка отмечена восклицательным знаком). Однако его можно определенно вывести из типа собственного шаблона (OneOfTheDerivedTypes). В моем случае я намерен наследовать AnotherObject с определенным шаблоном, поэтому я не хочу просто жестко кодировать тип возвращаемого значения для 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;
};
Одним из решений этой проблемы является указание дополнительного аргумента шаблона с именем ArbitraryType, как показано ниже:
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;
};
Затем программист должен указать оба параметра, где OneOfTheDerivedTypes — либо DerivedFloat, либо DerivedString, а ArbitraryType — float или string соответственно. Не очень хорошее решение, поскольку ArbitraryType полностью определяется выбором OneOfTheDerivedTypes.
Я думаю, что дополнительного шаблона (ArbitraryType в AnotherObject) можно было бы избежать, если бы Base возвращал экземпляр ArbitraryType в общедоступной функции (назовем ее ReturnInstanceOfArbitraryType()) и использовал decltype(OneOfTheDerivedTypes::ReturnInstanceOfArbitraryType()) внутри AnotherObject. Это кажется неэлегантным, потому что ReturnInstanceOfArbitraryType() в противном случае бесполезен (и должен быть общедоступным). Является ли это тем случаем, когда правильно использовать класс свойств? Есть ли лучшее решение? (Все еще разбираюсь с некоторыми из этих новых вещей С++ 11). Спасибо!
Base
вы можете иметьtypedef ArbitratyType TypeOfBase
позже, в производных классах вы можете использоватьTypeOfBase
вместоDerivedString::Base::ArbitraryType
в первом примере. - person Sergei Kulik   schedule 05.01.2016