2016-03-24 16 views
0

Özel liste uygulamasında bir öğe arayan bir işlev var. Bunu düzeltmek için, bu düzgün aşırı yükü yapabilirim ve aynı uygulamayı tekrar kullanmak için tek liner kullanabilirim, böylece mantığı kopyalamak zorunda kalmam.Bir const işaretçisi vektörünü const olmayan işaretçilerden oluşan bir vektöre const_cast nasıl?

const MyObject* findObject(const MyList& list) 
{ 
    //... 
} 

MyObject* findObject(MyList& list) 
{ 
    return const_cast<MyObject*>(findObject(const_cast<const MyList&>(list))); 
} 

sorun, ben reinterpret_cast gibi kaydı iptal edildi/non-taşınabilir kesmek engelleme bir vektör içine birden çok eleman işaretçileri dönmek gerekir kez yapılacak ne var?

std::vector<const MyObject*> findObject(const MyList& list) 
{ 
    //... 
} 

std::vector<MyObject*> findObject(MyList& list) 
{ 
    // this is sth I'm looking for: 
    const_element_cast<std::vector<MyObject*>>(findObject(const_cast<const MyList&>(list))); 
} 
+0

const_cast (liste) 'nin anlamı nedir? – SergeyA

+0

Argümanlardaki" const "belirteci, arayanın, kendisine iletilen verileri değiştirmeyeceği konusunda bir garantidir. Girilmesi gereken verilerin bir şartı değildir. Non-const verilerinde geçiş yapabilirsiniz. Yani const_cast (list) 'in anlamsız. Ayrıca, findObject() 'dan' const MyObject * 'döndürme de anlamsızdır. Nedenini anlamak için, bu snippet'i düşünün: const int C = 42; int i = C; –

+0

düzgün yazarak bu çocukça const_cast fikirlerinden sessizce uzaklaşın. Güvenlik silahlarını neden silahlara koyduğunu biliyorsun, değil mi? –

cevap

2

kolay çözüm yaklaşık const_cast unutup sadece açıkça hem aşırı yükleri uygulamaktır. Bu, standart kitaplık uygulamalarının yaptığı şeydir.

Örneğin, std::vectoroperator[] bir const olan ve olmayan const sürümü vardır. Hem VC++ hem de GCC, bu işleç için yinelenen uygulamalara sahiptir (sırasıyla, include/vector veya stl_vector.h dosyaları); Bu davranışı çoğaltmak için hiçbir const_cast püf noktasını kullanır. senin findObject uygulaması çok büyük ve karmaşık ise

Şimdi, o zaman ilk tercihi daha basit hale getirmek olmalıdır. Geçici bir çözüm olarak, bağımsız bir decltype son geri dönüş türünü kullanarak iç (özel veya başka erişilemeyen) şablon işlevi açısından her iki aşırı yüklenmeyi de uygulayarak, doğru const veya const dönüş türünü argüman aracılığıyla alın. (typeid uygulamanıza ürettiği isimlerin ne tür bağlı)

#include <iostream> 
#include <vector> 
#include <typeinfo> // just to demonstrate what's going on 

// simple example data structure: 
struct MyObject {}; 
struct MyList 
{ 
    MyObject elements[3] = { MyObject {}, MyObject {}, MyObject {} }; 
}; 

namespace internal 
{ 
    // &list.elements[0] will be either MyObject const* or MyObject* 
    template <class ConstOrNonConstList> 
    auto doFindObject(ConstOrNonConstList& list) -> std::vector<decltype(&list.elements[0])> 
    { 
     // let's say there was an immensely complicated function here, 
     // with a lot of error potential and maintenance nightmares 
     // lurking behind a simple copy & paste solution... 

     // just to demonstrate what's going: 
     std::cout << typeid(decltype(&list.elements[0])).name() << "\n"; 

     std::vector<decltype(&list.elements[0])> result; 
     for (auto&& element : list.elements) 
     { 
      result.push_back(&element); 
     } 
     return result; 
    } 
} 

std::vector<const MyObject*> findObject(const MyList& list) 
{ 
    std::cout << "const version\n"; 
    return internal::doFindObject(list); 
} 

std::vector<MyObject*> findObject(MyList& list) 
{ 
    std::cout << "non-const version\n"; 
    return internal::doFindObject(list); 
} 

int main() 
{ 
    MyList list1; 
    MyList const list2; 
    auto obj1 = findObject(list1); 
    auto obj2 = findObject(list2); 
} 

Örnek çıktı:

non-const version 
struct MyObject * 
const version 
struct MyObject const * 

Ama açıkçası, bunu olmaz Burada basit bir örnektir. Fazla tasarlanmış görünüyor ve belki de biraz fazla zeki. Aşırı zeki kod nadiren iyi bir fikir, çünkü insanları karıştırıyor.

+0

Bu teknik, Scott Meyer'in Etkili C++'sından ödünç alınmıştır. Kütüphane tasarımcıları bundan kaçınırsa, o zaman onun olumsuz tarafları nelerdir? Şimdiye kadar hiç bir şey göremiyorum. Ayrıca, çok büyük olsa bile, her zaman bir yöntemin yeniden işlenmesi mümkün/tavsiye edilebilir değildir. Örneğin, test edilmiş eski kodla uğraşmayı düşünün. Ve yine de, sonunda sadece sınır kontrol ve diğer temelleri olsa bile, bir kez yapıp iki kere kullandım, iki noktadan çoğaltmak yerine iki kere kullandım ve değişiklik yaparsa (her ikisini de senkronize etmek için geliştiriciye güvenmek istiyorum) gösterir: sık sık olmaz) – user1709708

İlgili konular