【问题标题】:C++ type casting pointers to constant variables指向常量变量的 C++ 类型转换指针
【发布时间】:2017-06-17 05:44:04
【问题描述】:

我希望有一种方法可以为具有大量混合类型的可访问(但不可编辑)数据成员的类编写单个 get 函数。使用包含成员地址的 void*-cast 副本的映射将起作用,如以下代码所示,但只要将“const”投入混合以强制执行只读,不出所料 C++ 吠叫说'const void*' 类型不能被重铸以适当地访问数据成员。以下代码适用于为混合数据类型的类编写单个 get 函数,但它有效地将 get 函数访问的所有数据成员公开(具体参见 memlist 类中的 get 函数)。

底线:

有没有办法使指针类型可转换,同时在实际内存位置保持只读?或者更根本的是,可以定义一个指向常量变量的类型转换指针吗?例如,在我看来,const type *var 为只读变量定义了一个只读/不可转换的地址,而我试图找到一些更像@987654325 的东西(到目前为止对我还没有工作) @,虽然我还没有找到任何关于此的文档。

#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

【问题讨论】:

  • 我为不得不维护这段代码的程序员感到抱歉。 C++ 有 std::any 这样的事情。
  • @PaulMcKenzie 谢天谢地,这只是我在玩指针......

标签: c++ pointers memory-management constants


【解决方案1】:

显示的代码设计得很糟糕,容我们说吧。

void* 与 C++ 中的类型系统一样接近于破坏类型系统。正如 cmets 中提到的,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。

【讨论】:

    【解决方案2】:

    经过进一步的探讨,我不得不恭敬地不同意之前在 cmets 和答案中的评估......自从发布这个问题以来,我遇到了许多标准 C 库中的函数其中 void * 类型很容易使用(http://www.cplusplus.com/reference/cstdlib/qsort/),更不用说它是依赖于程序员类型转换的 malloc 的返回类型(可能是 C/C++ 中使用最广泛的函数?)。另外,据我所知,std::any 是一个新的 c++17 类,那么您在 6 个月前如何回答这个问题?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-02
      • 2020-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多