Я прочитал статью Wikipedia о любопытно повторяющемся шаблонном шаблоне в C++ для того, чтобы сделать статичный (чтение: время компиляции) полиморфизм. Я хотел обобщить его так, чтобы я мог изменить типы возврата функций на основе производного типа. (Это кажется, что должно быть возможно, так как базовый тип знает производный тип от шаблонного параметра). К сожалению, следующий код не скомпилирует использование MSVC 2010 (у меня нет легкого доступа к gcc прямо сейчас, таким образом, я еще не попробовал его). Кто-либо знает почему?
template
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast(this)->foo();
}
};
template
class derived : public base > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived a;
}
BTW, у меня есть обходное решение с помощью дополнительных шаблонных параметров, но мне не нравится он---, это станет очень подробным при передаче многих типов цепочка наследования.
template
class base { ... };
template
class derived : public base,T> { ... };
Править:
Сообщение об ошибке, что MSVC 2010 дает в этой ситуации, error C2039: 'value_type' : is not a member of 'derived
g ++ 4.1.2 (с помощью codepad.org) говорит error: no type named 'value_type' in 'class derived
Я знаю, что это - в основном обходное решение, которое Вы нашли, и не любите, но я хотел зарегистрировать его и также сказать, что это - в основном текущее решение этой проблемы.
я искал способ сделать это некоторое время и никогда не находил хорошее решение. То, что это не возможно, является причиной почему в конечном счете, вещи как boost::iterator_facade<Self, different_type, value_type, ...>
потребность много параметров.
, Конечно, мы хотели бы, чтобы что-то что-то вроде этого работало:
template<class CRTP>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using ptr_type = typename CRTP::value_type*; // doesn't work, A is incomplete
};
template<class T>
struct A : incrementable<A<T>>{
void increment(){}
using value_type = T;
value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
, Если это было возможно, все черты производного класса могли бы быть переданы неявно ot базовый класс. Идиома, которую я нашел для получения того же эффекта, должна передать черты базовому классу полностью.
template<class CRTP, class ValueType>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using value_type = ValueType;
using ptr_type = value_type*;
};
template<class T>
struct A : incrementable<A<T>, T>{
void increment(){}
typename A::value_type f() const{return typename A::value_type{};}
// using value_type = typename A::value_type;
// value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
недостаток состоит в том, что к черте в производном классе нужно получить доступ с квалифицированным typename
, или повторно включил using
.