Бих искал да получа шаблонния тип на базовия клас вътре в обект, който притежава екземпляр на производния клас. Кодовият фрагмент по-долу няма да работи, защото 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 или низ. Не е добро решение, защото ArbitraryType е напълно специфициран чрез избора на OneOfTheDerivedTypes.
Мисля, че допълнителният шаблон (ArbitraryType в AnotherObject) може да бъде избегнат, като Base върне екземпляр на ArbitraryType в публична функция (наречете го ReturnInstanceOfArbitraryType()) и използвайте decltype(OneOfTheDerivedTypes::ReturnInstanceOfArbitraryType()) вътре в AnotherObject. Това изглежда неелегантно, защото ReturnInstanceOfArbitraryType() не е полезен иначе (и трябва да бъде публичен). Това случай ли е, когато правилното нещо, което трябва да направите, е да използвате клас черти? Има ли по-добро решение? (Все още разбирам някои от тези нови неща на C++11). Благодаря!
Base
можете да иматеtypedef ArbitratyType TypeOfBase
по-късно в производните класове, можете да използватеTypeOfBase
вместоDerivedString::Base::ArbitraryType
в първата си проба. - person Sergei Kulik   schedule 05.01.2016