【问题标题】:Set vector type at runtime在运行时设置向量类型
【发布时间】:2009-09-15 09:19:25
【问题描述】:

我有一个程序需要在程序执行时设置向量的类型(根据配置文件中的值)。

我试过这个:

int a = 1

if(a == 1)  vector<int> test(6);
else  vector<unsigned int> test(6);

test.push_back(3);

但这给了我:

Error   1   error C2065: 'test' : undeclared identifier

我不完全确定为什么,但我认为这是因为向量实际上并没有在编译时确定,因此编译器在编译其余代码时无法使用它。

有没有办法在运行时确定向量的类型,类似于我上面尝试的方法? 我试图在 if 之外创建一个版本,然后将其删除并在 IF 内重新编写新版本。然而,这感觉不对,无论如何我都无法让它工作。 谢谢。

【问题讨论】:

    标签: c++ vector runtime types


    【解决方案1】:

    它不起作用的原因是您分别在 if- 和 else- 块内声明向量,因此一旦该块结束,它们就会超出范围。

    有没有办法在运行时确定向量的类型,类似于我上面尝试的方法?

    不,变量的类型必须在编译时知道。您唯一的选择是将test.push_back(3) 行以及访问test 的任何后续代码放入if 和else 块中,或者避免代码重复到第二个模板化函数中。这可能如下所示:

    template <class T>
    do_something_with_test(vector<T>& test) {
        test.push_back(3);
        // work with test
    }
    
    void foo() {
        int a = 1
    
        if(a == 1) {
            vector<int> test(6);
            do_something_with_test(test);
        }
        else {
            vector<unsigned int> test(6);
            do_something_with_test(test);
        }
    }
    

    【讨论】:

    • 谢谢。我明白你在说什么。我将对此进行研究,并可能按照您的建议将我所有超出向量类型决定的代码放入模板化函数中。
    • 那行得通,花了一点时间来解决这个问题。谢谢。
    【解决方案2】:

    您遇到错误的确切原因对于初学者来说有点微妙,它涉及您正在创建的变量 test 的范围。简而言之,您是在 if 语句中创建向量,但当您要使用它时,它已不存在,因为它已超出范围。

    我已经用括号重新格式化了您的代码,以使这种效果更加明显。请注意,我的版本在语义上与您的版本相同,并且会给出相同的错误。

    if(a == 1)
    {
      vector<int> test(6);
    }
    else
    {
      vector<unsigned int> test(6);
    }
    
    test.push_back(3);
    

    也就是说,你想做的事情似乎有点奇怪,我想知道你的最终目标是什么。这并不是说没有办法做你想做的事,但我需要知道你的成功标准是什么,然后才能提出更合适的方法。

    【讨论】:

    • 谢谢。注意:显示的代码只是为了解释......实际程序处理二进制数据,可以在 32 或 64 位模式下运行。需要更改向量的类型以保存指向类(实际保存数据)的 64 位或 32 位大小的指针。这个类是一个模板类,所以我的向量的类型决定了我的模板类的类型。我明白你们对范围的看法。我目前正在试验是否可以将向量设置在 if 之外,然后在 if 循环中将其转换为 64 位。
    • 为什么要编写两批代码来处理 32 位或 64 位?您用于控制 32/64 版本的编译器开关将确定指针的大小和类型 - 只需一个指向您的类的指针向量,例如向量 测试;
    【解决方案3】:

    我不确定你为什么需要它,但我建议你尝试使用联合向量来解决你的问题,就像这样

    union DataType
    {
        int intVal;
        unsigned uintVal;
    }
    std::vector<DataType> vec;
    

    或者可能更优雅的方法是使用boost::variant 而不是联合。如果您向我们提供有关您的问题的更多详细信息,您可能会得到更好的答案。

    祝你好运!

    【讨论】:

    • 修复了格式,以便“”显示在“vector”中。
    【解决方案4】:

    您可以查看boost::any 以实现类似的效果。

    【讨论】:

      【解决方案5】:

      设置向量的类型(又名模板实例化)总是在编译时发生。有关更多说明,请查看Template metaprogramming 上的维基百科文章。

      【讨论】:

        【解决方案6】:

        如果你真的需要多态类型,也许你可以看看 boost::variant 类或类似的东西;
        这旨在模仿 C++ 中动态语言的一些行为,通常用于与它们交互(或实现)。 您可以创建一个“vector a”和 a.push_back(Variant((unsigned int)..)。推送的值的构造函数需要编译时类型。

        如果您希望值是同质的,也可以创建一个矢量化变体类来存储整个集合的类型信息。

        但是,如果没有这种机制,您更有可能获得所需的最终结果,可能需要重新编写程序以避免运行时类型检查(这很可能会首先否定使用 C++ 而不是另一种语言的一些好处)。

        您可以将依赖于类型的部分编写为模板(如上所述),并根据检查和调度一次的配置文件设置选择替代代码路径。这种编码风格在 c++0x 中使用 'auto' 和 decltype() 变得稍微容易一些。

        无符号值与有符号值的具体情况涉及允许多一位听起来不寻常,或者与增加的复杂性相比具有边际收益,但我可以很容易地想象一个可以在单精度和双精度浮点数之间切换的实现.

        另一个简单的选项是为类型进行编译时间设置(例如,作为构建设置或 makefile 中的定义引入),然后分发程序的多个版本,这在某些情况下可能有意义。但是,已经建议的模板更有可能是最有用的选项。

        【讨论】:

          【解决方案7】:

          在您的示例中,您在 if 语句的每个分支中创建了变量 test 的独立实例,每个分支都会立即超出范围。因此,当编译器到达test.push_back(3); 时,范围内没有test 变量,因此会出现错误。

          要解决您的问题,您不能与类型系统作斗争:假设 intunsigned int 是有问题的实际类型,您最好在整个过程中使用 vector&lt;int&gt;,假设您不这样做' t 实际上需要 unsigned int 的全部范围。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多