Can I put static_assert in class method if I never call this method?

  • A+
Category:Languages

This version doesn't compile at all:

struct A {     void foo() {         static_assert(0,"Fail");     } }; 

This version compiles without errors (at least in my version of compiler):

template <int x> struct B {     void foo() {         static_assert(x,"Fail");     } }; B<0> b; 

The second version fails to compile only when I call b.foo();, so I want to know is it permitted by the standard to use the second version if I never call method foo? Will all compilers behave in the same way? Isn't it undefined behavior?

I want to include static_assert in the code to forbid usage of some methods of a template class when some template parameters meet some criteria. Is it correct usage of static_assert?

I want to use this approach (I want to forbid usage of .z() when vector has only two dimensions) in this situation:

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

 


The bodies of a template class's methods are not instantiated unless called.

However, if we consider the instantiation of bodies of a template class's methods to be template instantiations (this is unclear in the standard), then there must be a valid set of template arguments that makes the body possible to instantiate; otherwise the program is ill-formed, no diagnostic required.

In your specific case, static_assert(x, "Fail") clearly has a valid instantiation (any x!=0). So you are safe.

However

void foo() {   static_assert(x&&!x, "Fail"); } 

isn't going to be safe; by my reading, that is an ill-formed program with no diagnostic required. On the other hand, my reading might be wrong; the standard is pretty oblique here.

The philosophical reason why the above is wrong is that it permits compilers to detect for impossible assumptions in static asserts; it lets the compiler check more things in the bodies of templates than the standard demands, which is I believe why the standard makes uninstantable templates ill-formed, and no diagnostic requried is because they don't want to have to force every compiler to do every kind of diagnostic for every kind of uninstantiable template (which requires solving Halt).

So philosphically, your static_asserts in non-template methods should be possible to pass for some template arguments passed to the containing template class.

Things get murkier when you have a template method to a template class which is impossible to instantiate for certain template arguments to the template class. But that is going down a rabbit hole.

I am sufficiently uncertain about that last case that I avoid doing it, and instead use CRTP to conditionally have the method exist or not.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: