是否可以在C ++中声明变量在switch范围之外?

时间:2015-10-06 13:02:57

标签: c++

简而言之,请考虑下面的(伪)代码:

switch (n) {
    case 15:
        (keyword) customtemplate<15> t_var; /* I want it to be outside of switch */
        break;
    case 255:
        (keyword) customtemplate<255> t_var; /* I want it to be outside of switch */
        break;
    default:
        break;
}

t_var.do_something();

我想知道是否有一些(keyword)使得跟随变量是全局的,或者在switch-case范围之外。

我想要这样一个奇怪的代码的原因是,我不能声明任意数量为n的模板变量,即:

int n = 15; // or int n = 255;
custometemplate<n> t_var; /* I can't do this */
t_var.do_something;

此帖中提到的customtemplateezpwd-reed-solomon中是RS<n,k>。我想声明RS<n, k>RS<15,2>RS<15, 4>RS<15, 7>RS<15, 11>RS<64, 32>RS<160, 128>。< / p>

5 个答案:

答案 0 :(得分:7)

简单的答案是&#34; NO&#34;!

在您的情况下,不同的模板实例只是一种不同的类型。

如果你可以做你想做的事情,问题就是如何处理这个任何类型的实例。你以后如何使用这个变量?

请记住:在编译期间创建模板实例!在运行时运行切换案例。

您的代码会产生与以下相同的问题:

switch (foo)
{
    case 1:
       int bar;
       break;

    case 2:
       float bar;
       break;
 }

 ??? and now how the compiler should handle two different types ???

再次:模板实例是不同的类型!

正如其他人已在此处提到的那样,您可以使用一种变体类型,它只包含给定类型列表的一个实例。它还包含一个实际存储在此变体实例中的类型的信息。

但我更喜欢使用可用的实现而不是编写自己的实现。为此,请参阅例如提升变体http://www.boost.org/doc/libs/1_58_0/doc/html/variant.html

但是根据我的经验作为简历:如果你觉得你需要一种变体类型,你就会强烈地证明你的设计。作为提示:如果您需要变体类型,您稍后会看到您每次处理此变体时都必须检查实际内容。我认为这通常违反了良好的OOP设计。它可以帮助,但我认为应该避免!

答案 1 :(得分:3)

如评论中所述,您可以使用共同的祖先基类:

#include <memory>
#include <iostream>

struct RS_Base
{
    virtual void do_something() = 0;
};

template<size_t n, size_t k>
struct RS : RS_Base
{
    void do_something() override {
        std::cout << "n=" << n << "k=" << k << std::endl;
    }
};


int main()
{
    int n = 15; 
    int k = 2;

    std::shared_ptr<RS_Base> t_var(nullptr);
    switch (n) {
        case 15:
            t_var = std::shared_ptr<RS_Base>(new RS<15,2>()); /* I want it to be outside of switch */
            break;
        case 255:
            t_var = std::shared_ptr<RS_Base>(new RS<255,2>()); /* I want it to be outside of switch */
            break;
        default:
            break;
    }

    if (t_var)
    {
        t_var->do_something();
    }
}

更新:外部struct / class的示例

#include <iostream>
#include <memory>

//External
template<size_t n, size_t k>
struct RS
{
public:
    void do_something() {
        std::cout << "n=" << n << "k=" << k << std::endl;
    }
};

//Internal
struct RSWrapper_Base
{
public:
    virtual void do_something() = 0;
};

template<size_t n, size_t k>
struct RSWrapper : RSWrapper_Base
{
private:
    RS<n, k> value;

public:
    void do_something() override
    {
        value.do_something();
    }
};

//Usage
int main()
{
    int n = 255; 
    int k = 2;

    std::shared_ptr<RSWrapper_Base> t_var(nullptr);
    switch (n) {
        case 15:
            t_var = std::shared_ptr<RSWrapper_Base>(new RSWrapper<15,2>()); /* I want it to be outside of switch */
            break;
        case 255:
            t_var = std::shared_ptr<RSWrapper_Base>(new RSWrapper<255,2>()); /* I want it to be outside of switch */
            break;
        default:
            break;
    }

    if (t_var)
    {
        t_var->do_something();
    }
}

更新:使用模板处理函数的示例

不能完全按照问题的要求工作,但可能仍然是解决问题的方法。

#include <memory>
#include <iostream>

template<size_t n, size_t k>
struct RS
{
    void do_something() {
        std::cout << "n=" << n << "k=" << k << std::endl;
    }
};

template<typename RS_Type>
void handleRS(RS_Type t_var)
{
    t_var.do_something();
};


int main()
{
    int n = 15;
    int k = 2;

    switch (n) {
    case 15:
        handleRS(RS<15, 2>());
        break;
    case 255:
        handleRS(RS<255, 2>());
        break;
    default:
        break;
    }
}

答案 2 :(得分:0)

我同意@Klaus的说法,这是不可能的;模板的不同实现是不同的类型,因此.do_something()调用(在完全实现的对象上调用,而不是v-tables可能进入混合的引用或指针)不可能知道哪个版本要调用的代码。

也就是说,模板引起的问题可以通过模板解决。而不是switch初始化某些内容以便在switch之后的代码中使用,或者在每个case中复制其他相同的代码(有效但丑陋;违反DRY),让case中的每个switch调用一个模板化函数,该函数可以适当地创建和使用模板化类型。您编写的函数的其余部分将迁移到此函数,该函数与您用于该类型的计数相同,并且每个switch的唯一操作将是return actionwrapper<15>(any, variables, beyond, t_var, from, current, scope, needed, to, perform, work);(其中非原始函数)理想情况下,变量通过引用,l值或r值传递,以避免复制构造。

答案 3 :(得分:0)

在switch语句中不允许某些变量声明的原因是:基于开关的控制流跳过变量初始化是非法的。 如果要在switch语句之外使用变量,请在切换之前声明它。

答案 4 :(得分:-1)

除了语言特定的考虑因素外,我想采用不同的方法;在Objective-C中称为对象冒充

您可以将任何类的任何实例作为某个类的某个实例引入,如下所示:

switch (someInstance) {
    case a:
    [ClassWillBePosed poseAsClass: [AClass class]];
    break;
    case b:
    [ClassWillBePosed poseAsClass: [BClass class]];
    break;
    default:
    ...
}

但是,我怀疑这是一个解决方案。