2016-05-27 3 views
1

コンパイル時には、概念的には私のために、リファクタリングの提案は歓迎されているので、このコンパイル方法は次のとおりです。プライベートデストラクタでテンプレートエラーをバイパスする

"検索"デストラクタがプライベートなのでコンパイルエラーが発生しましたが、ベースクラスの初期化でカスタムDeleterを提供して以来、私は検索ポインタでdeleteを使用しません。私は、コンパイラがそれを迂回する方法を知らないことを知っています。

エラーの説明: エラーC2248:プライベートメンバにアクセスすることはできません コンパイラが生成した「検索」クラスで宣言された「検索::〜検索」ここ

class Search 
{ 
public: 
static Search* New(/* */); // using a pool of already allocated objects to avoid expensive allocations 
    static void Delete(Search*); 

private: 
    Search(/* */) {/* */} 
    ~Search() {/* */} 
}; 


template<class T> 
class MyList 
{ 
    public: 
    typedef (*CustomDeleter) (T* pElement); 

    MyList(CustomDeleter lpfnDeleter = NULL) {}; 


    void Empty() 
    { 
     for (/**/) 
     { 
      if (m_pList[m_nListLastUsed]) 
      { 
       if (m_lpfnCustomDeleter == NULL) 
        delete m_pList[m_nListLastUsed]; // COMPILE ERROR HERE BECAUSE Search destructor is private BUT I won't use that instruction since 
                // I provided a custom Deletern I know that the compiler doesn't know that, how to bypass it 
       else 
        m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); 
      } 
     } 
    } 

    private: 
    T** m_pList; 
    CustomDeleter m_lpfnCustomDeleter; // Pointer to a custom deleter 
}; 

class Query : public MyList<Search> 
{ 
    public: 
    Query() : MyList<Search>(&Search::Delete) // I set a custom deleter since Search hides its destructor : is this the right way ? 
    {} 

    ~Query() 
    { 
     /****/ 
     Empty(); // PROBLEM HERE 
     /***/ 
    } 
}; 
+0

@Holt検索オブジェクトを削除したくないため、後で使用するために、検索対象をロックフリースタック(保存した後)に保存したい場合は、 – Aminos

+0

とお考えください* call *コードは無効な*コードが存在することを意味するものではありません。 'delete m_pList [m_nListLastUsed]; 'あなたが提供していない適切にアクセス可能なデストラクタを期待しています。したがって、コードは有効ではないため、エラーになります。私はそれが可能なsfinaeの選択肢を持っているかどうかを検討するために一瞬それをゲルにしなければならないでしょう。 – WhozCraig

+1

'm_pList'はどこにも定義されていません。投稿してください[MCVE](http://stackoverflow.com/help/mcve) –

答えて

3

「m_lpfnCustomDeleterがNULLになることはありませんことを確認しますかより良いnullptr。ユーザーがカスタムディテクタを提供していない場合は、デフォルトの「Deleter」に戻って確認することができます。

私は以下のようなものを好みます。 W/O C++ 11

  1. を想定し をリファクタリング

    #include <iostream> 
    
    template <typename PointerType> 
    struct DefaultDeleter { 
        void operator()(PointerType* ptr) { 
        std::cout << "Delete\n"; 
        } 
    }; 
    
    struct CustomDeleter { 
        void operator()(int* ptr) { 
        std::cout << "Custom int deleter" << std::endl; 
        } 
    }; 
    
    template <typename T, typename Deleter = DefaultDeleter<T>> 
    class Whatever 
    { 
    public: 
        Whatever() { 
        std::cout << "Cons\n"; 
        } 
        void deinit() { 
        Deleter d; 
        auto v = new T; 
        d(v); // Just for the sake of example 
        } 
    }; 
    
    int main() { 
        Whatever<char> w; 
        w.deinit(); 
    
        Whatever<int, CustomDeleter> w2; 
        w2.deinit(); 
        return 0; 
    } 
    

    更新:: W/Oコードは、この小さなメタプログラミングはあなたのコードベースに追加しました。

    名前空間には、私の{

     template <typename T, typename U> struct is_same { 
         static const bool value = false; 
         }; 
    
         template <typename T> 
         struct is_same<T, T> { 
         static const bool value = true; 
         }; 
    
         template <bool v, typename T = void> struct enable_if; 
    
         template <typename T = void> struct<true, T> { 
         typedef T type; 
         }; 
    
        } 
    
  2. はにあなたの空の機能を変更し

    空空()のための{ (/ **** /){ do_delete(); }}

 
    template <typename = 
        typename my::enable_if<my::is_same<T, Search>::value>::type> 
    void do_delete() { 
     assert (m_lpfnCustomDeleter != NULL); 
     m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); 
    } 

    void do_delete() { 
     delete m_pList[m_nListLastUsed]; 
    } 

あなたがC++ 11を使用している場合、あなたはいけない名前空間の下に '私' をメタプログラミングを記述する必要があります。単に 'my :: is_same'と 'my :: enable_if'を 'std :: is_same'と 'std :: enable_if'に置き換えてください。

注:上記のコードをコンパイルしてテストしていない。

+0

CustomDeleterは "MyList"に追加された機能なので、そのパラメータなしでMyListを使用して古いコードをリファクタリングしないようにNULLデフォルト値を使用しました。 – Aminos

+0

できる場合は、コードのリファクタリングを考慮する必要があります。何かがそれについて正しく感じない。 'm_pList'は何ですか?それが 'Search'へのポインタを保持しているならば、それを削除してそのデストラクタをプライベートとして作ることはできません。または、私が示したものと似たようなことをして、Searchの友人として 'CustomDeleter'を作ってください。 – Arunmu

+0

どうやらあなたのソリューションはきちんとしています...私はこれを試します...そうでなければ、MyListは他のクラスでも使われているソートされたリストですが、他のクラスはパブリックデストラクタを持っています。今は明らかですか? – Aminos

1

コードは残りの部分から削除を行っている別:

 if (m_pList[m_nListLastUsed]) 
     { 
      if (m_lpfnCustomDeleter == NULL) 
       delete m_pList[m_nListLastUsed]; // COMPILE ERROR HERE BECAUSE Search destructor is private BUT I won't use that instruction since 
               // I provided a custom Deletern I know that the compiler doesn't know that, how to bypass it 
      else 
       m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); 
     } 

にコールすることにより、上記のコードを置き換えます

custom_delete(m_pList[m_nListLastUsed]); 

その後、あなたのリストクラス、ドン」の方法として、それを追加tは同様<type_traits>を含めることを忘れ:

std::enabled_if<std::is_destructible<T>::value, void>::type custom_delete(T* ptr) { 
    /* Note: this isn't pre-2000 anymore, 'lpfn' as a prefix is horrible, 
     don't use prefixes! */ 
    if (m_lpfnCustomDeleter) { 
     m_lpfnCustomDeleter(ptr); 
    } else { 
     delete ptr; 
    } 
} 

std::enabled_if<!std::is_destructible<T>::value, void>::type custom_delete(T* ptr) { 
    if (!m_lpfnCustomDeleter) { 
      throw "No custom deleter for a non destructible type!"; 
    } 
    m_lpfnCustomDeleter(ptr); 
} 

enabled_ifますそのオブジェクトがプライベートなデストラクタを持っている場合、できるだけそのオブジェクトがdeleteのリストに存在しないようにしてください。

また、カスタム演算子として機能する構造体(または関数)を、リストの2番目のテンプレート引数として渡すこともできます。デフォルト値はdelete演算子を呼び出し、次にこの構造体をポインタで直接呼び出します。 Arunmuのanserで。

関連する問題