如果我从不调用static_assert,可以将其放在类方法中吗?

时间:2018-07-24 18:23:08

标签: c++ static

此版本完全无法编译:

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;
};

4 个答案:

答案 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

Demo

答案 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,可以将它放在类方法中吗?

  

静态断言声明可能会出现在名称空间和块作用域中   (作为块声明)和在类体内(作为成员)   声明)

是的,可以。