这个版本根本不编译:
struct A {
void foo() {
static_assert(0,"Fail");
}
};
Run Code Online (Sandbox Code Playgroud)
这个版本编译没有错误(至少在我的编译器版本中):
template <int x>
struct B {
void foo() {
static_assert(x,"Fail");
}
};
B<0> b;
Run Code Online (Sandbox Code Playgroud)
第二个版本只有在我调用时才能编译b.foo();,所以我想知道如果我从不调用方法,标准是否允许使用第二个版本foo?所有编译器都会以相同的方式运行吗?是不是未定义的行为?
我希望static_assert在代码中包含一些模板参数满足某些条件时禁止使用模板类的某些方法.这是正确的用法static_assert吗?
.z()在这种情况下,我想使用这种方法(我想禁止在vector只有两个维度时使用):
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;
};
Run Code Online (Sandbox Code Playgroud)
这里的行为是明确定义的.这里的显着差异在于,在第二种情况下,结果static_assert取决于模板参数,因此在实例化该方法之前不会解析它.如果它不依赖于模板参数那么它会像第一种情况一样失败而不实例化任何东西:
template <int x>
struct B {
void foo() {
static_assert(0,"Fail");
}
};
Run Code Online (Sandbox Code Playgroud)
是的,当某些模板参数符合某些标准时,禁止使用模板类的某些方法是正确使用static_assert.我甚至会说这是禁止方法的首选方法,因为与通常的模板实例化失败乱码相比,它可能会产生更可读的错误消息(即使有可能的修复建议).
除非被调用,否则模板类方法的主体不会被实例化。
然而,如果我们将模板类方法的主体实例化视为模板实例化(这在标准中并不清楚),那么必须有一组有效的模板参数使主体可以实例化;否则程序格式错误,无需诊断。
在您的具体情况下,static_assert(x, "Fail")显然有一个有效的实例化(任何x!=0)。所以你很安全。
然而
void foo() {
static_assert(x&&!x, "Fail");
}
Run Code Online (Sandbox Code Playgroud)
不会安全;根据我的阅读,这是一个格式不正确的程序,不需要诊断。另一方面,我的阅读可能是错误的;这里的标准是相当倾斜的。
上述错误的哲学原因是它允许编译器检测静态断言中不可能的假设;它让编译器检查模板主体中比标准要求更多的东西,这就是我相信为什么标准使不可实例化模板格式错误的原因,并且不需要诊断是因为他们不想强迫每个编译器都这样做每种不可实例化模板的每种诊断(这需要解决 Halt)。
因此从哲学上讲,static_assert非模板方法中的 s 应该可以传递一些传递给包含模板类的模板参数。
当模板类有一个模板方法时,事情会变得更加模糊,而该模板方法无法为模板类的某些模板参数实例化。但这正在陷入兔子洞。
我对最后一种情况非常不确定,因此我避免这样做,而是使用 CRTP 有条件地让该方法存在或不存在。
| 归档时间: |
|
| 查看次数: |
442 次 |
| 最近记录: |