有一个我正在重构的课程,目前有一个方法:
void resize(size_t sz)
在当前的代码库中,sz始终为0,1,2或3。 底层类正在从动态分配更改为maxsize == 3的预分配数组。
如果有人试图调整为sz> 3,怎么会出现构建时错误? 添加运行时检查很容易。但我宁愿让编译时检查更快失败。
我不想更改任何使用入站的整数文字进行调用的现有代码,例如:
x.resize(2)
仍应按原样编译。
但如果有人出现并试图
x.resize(4)
or
x.resize(n)
它应该无法编译或链接。
我在想一个专门针对int的模板,除了{0,1,2,3}之外的任何其他内容都是未定义的。但我不确定如何在标准c ++的范围内做到我想做的事。
编辑:
我应该详细说明我使用模板的想法。我非常愿意更改resize函数的声明。我不愿意更改主叫代码。
e.g。我在想像
void resize( ConstructedFromLiteral<0,3> sz)
或
void resize( ConstructedFromLiteral<0> sz)
void resize( ConstructedFromLiteral<1> sz)
void resize( ConstructedFromLiteral<2> sz)
void resize( ConstructedFromLiteral<3> sz)
答案 0 :(得分:6)
您无法通过编译时检查运行时值。想象一下,如果你说,
resize(read_some_number_from_disk());
编译器应如何检查?
但是,可以使该函数成为模板,因为模板参数在编译时已知:
class Foo
{
template <unsigned int N> void resize()
{
static_assert(N < 4, "Error!");
//...
}
//...
};
如果你没有静态断言,你可以装配你自己的静态断言类,它将无法编译:
template <bool> struct ecstatic_assert; // no definition!
template <> struct ecstatic_assert<true> { } ;
用法:
... resize ... { ecstatic_assert<N < 4> ignore_me; /* ... */ }
答案 1 :(得分:3)
我在编译时使用static_assert
来检查:
struct foo {
template <int N>
void resize() {
static_assert(N >= 0 && N < 4);
}
};
你在C ++ 11中内置了static_assert
,但它也是easy enough to implement in C++03。与专业化相比,它可以避免一些繁琐的代码重复。
答案 2 :(得分:1)
你不能这样做。您不能保持函数调用按原样调整大小,并在编译时检查n
,因为它是运行时值。您将需要重构代码以获得编译时错误(例如std / boost static_assert)。
答案 3 :(得分:0)
您可以为整数{0,1,2,3}创建四个公共内联专用模板。这些是简单的单行函数,可以为任何int调用私有的普通函数。
编辑:对于那些说使用专门模板无法完成的反对者(为什么是downvotes?):
class Demo {
private:
template<int MyInt>
void PrivateFunction() {
cout << MyInt << endl;
}
public:
template<int MyInt> void PublicFunction();
template<> void PublicFunction<0>() { PrivateFunction<0>(); }
template<> void PublicFunction<1>() { PrivateFunction<1>(); }
template<> void PublicFunction<2>() { PrivateFunction<2>(); }
template<> void PublicFunction<3>() { PrivateFunction<3>(); }
};
尝试调用Demo :: PublicFunction&lt; 4&gt;(),您将收到链接器错误。如果您没有/不想创建static_assert,那么完成同样的事情并且很有用。
正如其他人所提到的,检查参数的值不是那么容易......
答案 4 :(得分:-1)
出于明显的原因,我不喜欢这个答案,但它确实满足了您的要求:
struct x {
void true_resize(int n) { }
template <int N> void template_resize();
};
template<> void x::template_resize<0>() { true_resize(0); }
template<> void x::template_resize<1>() { true_resize(1); }
template<> void x::template_resize<2>() { true_resize(2); }
template<> void x::template_resize<3>() { true_resize(3); }
#define resize(x) template_resize<x>();
int main () {
x x;
x.resize(2);
x.resize(4);
}
如果不明显,#define
不遵守C ++范围规则,因此将名称resize
用于所有其他用途。