2017-08-24 21 views
0

以下のコードを最適化するために、メンバ関数str1str2のいずれかにポインタを渡すと有益になると思われます。引数はfill_vecに2つの明示的なループがあるのではなく、fill_vecになります。C++で引数としてメンバ関数へのポインタを渡します。

C++ 11でこれを行う方法がありますか?あるいは、別の戦略を提案していますか?


#include <iostream> 
#include <vector> 
#include <map> 

class Base 
{ 
    private: 
    std::map<int, std::string> m_base1, m_base2; 
    std::vector<std::string> m_str1 = {"one", "two", "three"}; 
    std::vector<std::string> m_str2 = {"four", "five", "six"}; 

    public: 
    std::vector<std::string> &str1() { return m_str1; } 
    std::vector<std::string> &str2() { return m_str2; } 

    std::map<int, std::string> &base1() { return m_base1; } 
    std::map<int, std::string> &base2() { return m_base2; } 
}; 

template <typename T> 
void fill_vec(T *b) 
{ 
    size_t counter = 0; 
    for (const auto &str_iter : b->str1()) 
     (b->base1())[counter++] = str_iter; 

    counter=0; 
    for (const auto &str_iter : b->str2()) 
     (b->base2())[counter++] = str_iter; 
} 

int main(int argc, char *argv[]) 
{ 
    Base *b = new Base; 
    fill_vec(b); 

    return 0; 
} 
+0

あなたは 'base1' /' BASE2へのポインタを渡す必要はありません渡す方法と同じように働いています'でも? –

+0

@ChrisDrew現在のデザインではありません。 – N08

+1

なぜベクトルサイズが同じであるので、1つのループを使用しないのですか? – Griffin

答えて

0

推奨プラクティスはfill_vec()は、好ましくは、コンストラクタから呼び出さベースのメンバー、であることを指示しますので、オブジェクトは右の作成後に使用する準備ができているでしょう。

しかし、マップm_base1とm_base2は定数なので、m_str1とm_str2を削除し、m_base1とm_base2を静的にして、コンストラクタで直接初期化する必要があります。

また、可能な限りスマートポインタを使用する必要があります。

これは与える:

#include <iostream> 
#include <vector> 
#include <map> 
#include <string> 
#include <memory> 

class Base 
{ 
    private: 
    static std::map<int, std::string> m_base1, m_base2; 

    public: 
    Base(); // WARNING !! must create a object before using maps! 

    static const auto & base1() { return m_base1; } 
    static const auto & base2() { return m_base2; } 
}; 


// in base.cpp 

std::map<int, std::string> Base::m_base1; 

Base::Base() 
{ 
    if (m_base1.empty()) 
    { 
     m_base1[0] = "one"; 
     m_base1[1] = "two"; 
     m_base1[2] = "three"; 
    } 
    if (m_base2.empty()) 
    { 
     m_base2[0] = "four"; // doesn't look right, but equivalent to original code 
     m_base2[1] = "five"; 
     m_base2[2] = "six"; 
    } 
} 


// in your main module.. 

int main(int argc, char *argv[]) 
{ 
    // auto b = std::unique_ptr<Base>(new Base{}); 
    // this would be best since Base is very small. 
    Base b; 

    // this prints the string "two six" 
    std::cout << b.base1().at(1) << " " << b.base2().at(2) << '\n'; 

    return 0; 
} 
+1

彼の 'map'は0ベースですか、いいえ? 'm_base1 [0] =" one "; – pingul

+0

いいえ、マップは_not_ 0ベースで、std :: map は任意の整数値を文字列にマップします。 –

+0

もちろん、m_base1 [counter ++]を 'counter = 0'とすると0と評価されます。また、' m_base1、m_base2'のシグネチャを変更したことに注意してください。 – pingul

0

ことが可能ですが、私は、上記のコメントに基づいて、それの実用性を確認します。

このような何かが働くだろう:

template <typename T> 
void fill_vec(Base* obj, std::map<int, std::string>& (T::*mapv)(), std::vector<std::string>& (T::*vec)()) 
{ 
    size_t counter = 0; 
    for (const auto &str_iter : (obj->*vec)()) 
     (obj->*mapv)()[counter++] = str_iter;  
} 

int main(int argc, char *argv[]) 
{ 
    Base *b = new Base; 
    fill_vec(b, &Base::base1, &Base::str1); 

    return 0; 
} 

これは通常pointer to member fields

関連する問題