Miguel P
Miguel P

Reputation: 1292

Static assertion on template parameter not called

Assuming these two helper structs:

struct A { static constexpr bool Value = false; };
template <bool DEFERRED> struct B { static_assert(DEFERRED, "Failed"); };

And the follow class that uses it:

class XYZ {
public:
    template <class X = A, class Y = B<X::Value>> int SomeFunction() {...}

....
int main() {
    XYZ xyz;
    xyz.SomeFunction();
}

I don't see why the static assertion is not called, since template boolean DEFERRED should evaluate to false. However when I instantiate template type Y inside the function body, the static assertion is called.

Is there a way to trigger the static_assert evaluation without instantiating template type Y? (Or an easier / smarter way)

EDIT: I should mention I'm using GCC 5.0

Thank you.

Upvotes: 2

Views: 856

Answers (3)

Miguel P
Miguel P

Reputation: 1292

I think my question was misunderstood. My issue was that I was expecting the compiler to evaluate the body when the type was instantiated, not when it was used in a declaration. Either way I resolved my issue by doing the following (Using the boilerplate code):

template <bool DEFERRED> struct B {
    static constexpr bool Proxy = DEFERRED;
    static_assert(Proxy , "Failed");
};
template <class X = A, bool T = B<X::Value>::Proxy> int SomeFunction() {...}

Which forced the compiler to evaluate the body and trigger any static assertions.

Upvotes: 1

Pavan Chandaka
Pavan Chandaka

Reputation: 12811

since template boolean DEFERRED should evaluate to false (in your question)....

This is because of the constexpr in struct A.

constexpr specifier makes it possible to evaluate the bool value at compile time

Take out constexpr and build, you will notice the difference.

Why your static_assert is not working:

static_assert expects a bool_constexpr.

DEFERRED is just bool and the value is known inside the template class body only if we instantiate.

Try with below code, I added another bool constexpr inside struct B naming test. And pass that variable to static_assert. Now your static_assert works.

//g++  5.4.0

#include <iostream>

struct A { static constexpr bool Value = false; };
template <bool DEFERRED> struct B { 
    static constexpr bool test =  false;
     static_assert(test, "Failed");
};

class XYZ {
public:
    template <class X = A, class Y = B<X::Value>> int SomeFunction()
    {
        return 0;
    }
};


int main()
{
    XYZ xyz;
    xyz.SomeFunction();
}

You will notice the output:

source_file.cpp:8:6: error: static assertion failed: Failed
      static_assert(test, "Failed");
      ^

Now change the test value in struct B to true.

It works, no errors.

There is another scenario, assign DEFERRED to test variable as shown below:

template <bool DEFERRED> struct B { 
    static constexpr bool test =  DEFERRED;
     static_assert(test, "Failed");
};

The above said static_assert works only if you instantiate in main(), something like below.

B<false> b;

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409442

You can see a class as a blueprint for an object, and you can see a template as a blueprint for a class.

A template is just a template, it is not a class until you instantiate the template into a class, which you don't do until the declaration of the xyz variable.

Upvotes: 1

Related Questions