Howard Hinnant's method (hash_append
aşırı yüklere dayalı genel karma) kullanılarak gerçekleştirilen bir karma işlemim var.Karma polimorfik tip doğru yol
Bu yöntemin amacı, hesaplamaların sonucunu "hatırlamak" için sınıfların karmaşasını yaratmaktır (bu cevabın sonuna bakın), bu yüzden bazı sorunlarla karşılaşıyorum. Ben Input
karma istersem gibi bir şey olacak,
struct A {
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
int do_stuff() const override { return u; }
};
struct Input {
A const& a; // store a reference to an instance of B or C
};
Şimdi:: Ben bir aşırı ihtiyaç
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, Input const& input) {
hash_append(h, typeid(input));
hash_append(h, typeid(input.a));
}
Özellikle, karma gereken aşağıdaki olası Input
sınıfını dikkate hash_append
A
için: buraya
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, A const& a) {
hash_append(h, typeid(a));
}
sorun olduğunuçalışma zamanı türüne bağlı, hash'a ek bilgi eklemem gerekecek, ör. C
için u
'u eklemeliyim.
Aşağıdaki çözeltiler (ve sakıncaları) düşündü:
typeid()
karma eklenebilir, belirli bir değer verirA
için sanal bir yöntem eklemek ama:- Bu,
A
'un içindeA
'un amacı ile ilgili olmayan bir yöntemin eklenmesi anlamına gelir, bu yüzden bu fikri gerçekten sevmiyorum (özellikle birden fazlaA
benzeri sınıfları olduğu için); Bu yöntem, tüm devralma sınıfları için benzersiz bir döndürme türüne sahip olacağından,hash_append
kavramını bozar.
- Bu,
hash_append
içindekidynamic_cast
bir grup var: BenA
benzer birden sınıfları varsa- ben özellikle ... Bu oldukça çirkin buldum;
- Bu hataya açık: Birisi
A
'un yeni bir çocuğunu eklerse vehash_append
'un içine bir dynamic_cast eklemezse.
kendini türünü değiştirmek veya dynamic_cast
bir grup güvenmek zorunda kalmadan, bir polimorfik tür karma bir yolu var mı?
bu nihai hedefi bazı ağır fonksiyonların sonuçlarını memoize muktedir olduğunu. benim uygulamasının temel yapısını kabaca anlatmama izin verin:
struct Input { };
struct Result { };
Result solve(Input const&);
solve
fonksiyon-hesaplama ağırdır, bu yüzden örneğin Input
s karmasını kullanarak dosyada önceki hesaplama sonuçlarını kaydetmek istediğinizgibi bir şey:
// depends on hash_append
std::string hash(Input const&);
Result load_or_solve(Input const& input) {
auto h = hash(input);
Result result;
if (exists(h)) { // if result exists, load it
result = load(h);
}
else { // otherwize, solve + store
result = solve(input);
store(h, result);
}
return result;
}
load
ve store
yöntemleri yüklemek ve dosyaları mağaza sonuçları olur, hedef Değişik değerler arasındaki çözümler memoize etmektir.
Yukarıdaki sonuçlarla uğraşmak zorunda kalmadan bu sonuçların nasıl okunacağı konusunda öneriniz varsa, bunları okumaktan memnuniyet duyarız.
ve B' ve 'C' için uygun versiyonları isteği gönderme:
İşte fikir göstermek gerekir kod demet 'türünü geri aldığınızda, ama tam olarak aradığınızı düşünmüyorum. Bunu düşündün mü? Bunun dezavantajı, bir ziyaretçi kabul etmek için bu sınıflara katmanı eklemeniz gerektiğidir. Sizin için işe yarayabilirse, yorumu daha ayrıntılı bir cevaba koyabilirim. – skypjack
@skypjack Üzgünüm Ne demek istediğini tam olarak anlamadım - anlamını göstermek için küçük bir örnek yazabilir misin? – Holt
[Bu hat boyunca] bir şey demek istiyorum (http://coliru.stacked-crooked.com/a/c1b5c249535f7590). Bu çalışan bir örnek değil ama siz bu fikri almalısınız. Maalesef, örnek kodunuz somut bir örnek alabilmek için çok fazla kod içermiyor, üzgünüm. Ve elbette, 'HashVisitor', variadic şablonlar ve doğrudan miras kullanarak, (en azından, yeni bir tip tanımladığınızda her zaman değiştirmeniz gerekmeyecek şekilde tasarlanmış) _simplified_ olabilir, ancak tanımladığım yol daha kolay olmalıydı. anlamak. – skypjack