2017-06-17 4 views
0

アクセス可能な(ただし編集可能ではない)データメンバが混在しているクラスに対して、単一のget関数を記述することができます。次のコードに見られるように、メンバーのアドレスのvoid * -castコピーを保持するマップの使用はうまくいくが、 'const'が読み込み専用を強制するためにミックスに投入されるとすぐに、 'const void *'型は、データメンバーに適切にアクセスするために再作成できません。次のコードは、混合データ型のクラスに対して単一のget関数を記述するために機能しますが、すべてのデータメンバーをget関数でアクセスするようにしています(具体的には、クラスのget関数参照)。定数変数へのC++型のキャストポインタ

ボトムライン:

リードオンリー実際のメモリ位置に保持したまま、ポインタは型キャスト可能にする方法はありますか?あるいは、もっと基本的には、定数変数への型キャスト可能なポインタを定義できますか?例えば、const type *varは、読み取り専用の変数にはキャスト可能な読み取り専用のアドレスを定義していますが、私は何か(これはまだ私のために働いていませんでした)を探していますが、type * const varのようにこれに関する文書を見つけることができませんでした。

#include <iostream> 
#include <string> 
#include <map> 

class A{ 
public: 
    A(int a, double b): a(a), b(b) {}; 
private: 
    int a; 
    double b; 

    friend std::ostream& operator<<(std::ostream& os, A& rhs); 
}; 

class memlist{ 
public: 
    memlist(int param1, double param2) 
    { 
     myint = new int(param1); 
     mydouble = new double(param2); 
     myclass = new A(param1,param2); 

     getMap["myint"] = myint; 
     getMap["mydouble"] = mydouble; 
     getMap["myclass"] = myclass; 
    } 
    ~memlist() 
    { 
     delete myint; 
     delete mydouble; 
     delete myclass; 
    } 
    void* get(std::string param) {return getMap[param];}; 
private: 
    int *myint; 
    double *mydouble; 
    A *myclass; 

    std::map<std::string,void*> getMap; 
}; 

std::ostream& operator<<(std::ostream& os, A& rhs){ 
    os << rhs.a << std::endl << rhs.b; 
    return os; 
}; 

int main(){ 
    int myint = 5; 
    double mydbl = 3.14159263; 
    memlist mymem(myint,mydbl); 

    std::cout << *(int*)mymem.get("myint") << std::endl; 
    std::cout << *(double*)mymem.get("mydouble") << std::endl; 
    std::cout << *(A*)mymem.get("myclass") << std::endl; 
    *(int*)mymem.get("myint") = 10; 
    std::cout << *(int*)mymem.get("myint") << std::endl; 

    return 0; 
} 

出力:

5 
3.14159 
5 
3.14159 
10 
+5

このコードを維持しなければならないプログラマには申し訳ありません。 C++には、このようなもののために 'std :: any'があります。 – PaulMcKenzie

+0

[std :: any usage](http://coliru.stacked-crooked.com/a/af4a1032226f6d60) – PaulMcKenzie

+0

@PaulMcKenzieありがたいことに、私はポインタで遊んでいます... – charlestoncrabb

答えて

1

コード示すには非常に、我々は病気に設計された、と言うものとされます。

void*は、C++での型システムの破壊に近いです。コメントに記載されているように、std::anyはこれに対するより良い解決策です。

これは、タイプセーフな方法で質問に示したことを実装するのに挑戦したと言いました。それはあまりにも少なく言って、残酷でした。

#include <iostream> 
#include <type_traits> 

using namespace std; 

template<typename> 
struct is_str_literal : false_type {}; 

template<size_t N> 
struct is_str_literal<const char[N]> : true_type {}; 

template<typename T> 
struct is_str_literal<T&> : is_str_literal<T> {}; 

template<typename T> 
constexpr bool is_str_literal_v = is_str_literal<T>::value; 

constexpr bool samestr(const char* arr1, const char* arr2, size_t n) 
{ 
    return n == 0 ? arr1[0] == arr2[0] : 
        (arr1[n] == arr2[n]) && samestr(arr1, arr2, n - 1); 
} 

template<size_t N1, size_t N2> 
constexpr bool samestr(const char (&arr1)[N1], const char (&arr2)[N2]) 
{ 
    return N1 == N2 ? samestr(arr1, arr2, N1 - 1) : false; 
} 

constexpr char myint[] = "myint"; 
constexpr char mydouble[] = "mydouble"; 
constexpr char myclass[] = "myclass"; 

struct S 
{ 
    template<const auto& name> 
    const auto& get() 
    { 
     static_assert(is_str_literal_v<decltype(name)>, "usage: get<var name>()"); 
     if constexpr(samestr(name, ::myint)) 
      return myint; 
     if constexpr(samestr(name, ::mydouble)) 
      return mydouble; 
     if constexpr(samestr(name, ::myclass)) 
      return myclass; 
    } 

    int myint; 
    double mydouble; 
    char myclass; 
}; 

int main() 
{ 
    S s; 
    s.myint = 42; 
    s.mydouble = 10.0; 
    s.myclass = 'c'; 
    cout << s.get<myint>() << endl; 
    cout << s.get<mydouble>() << endl; 
    cout << s.get<myclass>() << endl; 
} 

Live

これはC++ 17を使用しています。

+0

これはかなりクールです、ありがとう:) – charlestoncrabb

0

私は、この質問を投稿して以来、標準のCライブラリの多くの関数に出くわしました。 (http://www.cplusplus.com/reference/cstdlib/qsort/)、プログラマーの型キャストに依存するmallocの戻り型(おそらくC/C++で最も広く使われている関数でしょう)はもちろんです。また、私の知る限りでは、std :: anyは新しいC++ 17クラスですので、6か月前にこの質問にどのように答えてください。

関連する問題