此版本完全无法编译:
struct A {
void foo() {
static_assert(0,"Fail");
}
};
此版本编译无误(至少在我的编译器版本中):
template <int x>
struct B {
void foo() {
static_assert(x,"Fail");
}
};
B<0> b;
仅当我调用b.foo();
时第二个版本才能编译失败,所以我想知道如果我从不调用方法foo
的话,标准允许使用第二个版本吗?所有编译器的行为都一样吗?这不是未定义的行为吗?
我想在代码中包含static_assert
,以在某些模板参数满足某些条件时禁止使用模板类的某些方法。是static_assert
的正确用法吗?
在这种情况下,我想使用这种方法(当向量只有二维时,我想禁止使用.z()
)
template <typename T, int D>
struct MyVecctor {
MyVecctor() : data({})
{}
template <typename... Args>
MyVecctor(Args... args) : data({args...})
{
static_assert(D > 0);
static_assert(sizeof...(args) == D);
}
T& operator[] (std::size_t index) {
return data[index];
}
T& x() {
static_assert(D>=1);
return data[0];
}
T& y() {
static_assert(D>=2);
return data[1];
}
T& z() {
static_assert(D>=3);
return data[2];
}
std::array<T, D> data;
};
答案 0 :(得分:5)
这里的行为是明确定义的。此处的显着区别是,在第二种情况下,static_assert
的结果取决于模板参数,因此在实例化此方法之前不会解析它。如果它不依赖于模板参数,则它将失败,就像在第一种情况下不实例化任何东西一样:
template <int x>
struct B {
void foo() {
static_assert(0,"Fail");
}
};
是的,当某些模板参数满足某些条件时,禁止使用模板类的某些方法是static_assert
的正确用法。而且我什至会说这是一种禁止方法的首选方法,因为与通常的模板实例化失败事件相比,它可能会产生更具可读性的错误消息(即使有潜在的修复建议)。
答案 1 :(得分:2)
除非被调用,否则不会实例化模板类的方法的主体。
但是,如果我们认为模板类方法的主体的实例化是模板实例化(标准中尚不清楚),则必须有一组有效的模板参数来使主体可以实例化。否则程序格式错误,无需诊断。
在您的特定情况下,static_assert(x, "Fail")
显然具有有效的实例化(任何x!=0
)。所以你很安全。
但是
void foo() {
static_assert(x&&!x, "Fail");
}
不会很安全;根据我的阅读,这是一个格式错误的程序,不需要诊断。另一方面,我的阅读可能是错误的。这里的标准很斜。
上述错误的哲学原因是,它允许编译器检测静态断言中不可能的假设;它使编译器可以检查模板主体中的更多而不是标准要求,这就是为什么我相信该标准使难以识别的模板格式错误,并且没有诊断要求的原因,因为它们不想必须迫使每个编译器对每种无法实例化的模板(需要解决Halt)进行每种诊断。
从哲学上讲,应该将非模板方法中的static_assert
传递给传递给包含模板类的某些模板参数。
当您具有模板类的模板方法时,事情变得更加晦涩,无法为该模板类的某些模板参数实例化。但这是一个兔子洞。
对于最后一种情况,我有足够的不确定性,我避免这样做,而是使用CRTP来有条件地确定该方法是否存在。
答案 2 :(得分:2)
对于C ++ 2a,您可以使用 spplot(zn, scales = list(draw = FALSE),
col.regions = terrain.colors(100)) +
layer(sp.polygons(npadmin1, lwd = 1))
:
requires
答案 3 :(得分:1)
Static Assertion static_assert(bool_constexpr, message)
执行编译时断言检查。
如果bool_constexpr返回true,则此声明无效。 否则,将发出编译时错误以及消息文本(如果有) 诊断消息中包含任何内容。
您的代码为static_assert(0,"Fail")
,因此它将0
置为有效。但是,如果布尔表达式依赖于模板参数(或函数参数),则它在编译时没有值(除非您使用默认值),并且不能断言。
static_assert(x,"Fail")
可以断言,如果编译器知道x= false
。仅使用B<0> b
对于编译器是不够的。该断言在foo()
内部完成。如果使用了该成员,则意味着该成员函数已实例化,则编译器会声明。
如果我从不调用static_assert,可以将它放在类方法中吗?
静态断言声明可能会出现在名称空间和块作用域中 (作为块声明)和在类体内(作为成员) 声明)
是的,可以。