简而言之,请考虑下面的(伪)代码:
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;
此帖中提到的customtemplate
在ezpwd-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>
答案 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:
...
}
但是,我怀疑这是一个解决方案。