willpett
willpett

Reputation: 91

When does gcc compile unused template code?

I have the following (admittedly contrived) code that compiles just fine in gcc 6, but doesn't compile in gcc 7. Notice the use of an undeclared constructor in the definition of bar. This should print an error if the function is ever referenced elsewhere in the code (uncommenting foo.bar() causes gcc 6 to print an error). However, gcc 7 prints an error even if the function is not used.

Some changes cause the code to also compile with gcc 7 (e.g. if B is replaced with T in the definition of A), while some changes cause it to fail with gcc 6 (e.g. if this-> is not used). What's going on here? When does gcc decide to compile unused template code? Do different versions of gcc use different rules to decide?

struct B {};

template <typename T>
struct A {

    B* bar()
    {
        // undeclared constructor
        return new B(this->b);
    }

    B* b;
};

int main (int argc, char* argv[])
{
    A<int> foo;

    //foo.bar();
}

Upvotes: 2

Views: 542

Answers (2)

user2100815
user2100815

Reputation:

Perhaps I'm missing something, but you appear to be trying to construct a B object from a B pointer. And there is no default constructor that does that. So surely you want:

struct B {
    B( B * b ) {
    }
};

Upvotes: 0

John Zwinck
John Zwinck

Reputation: 249153

A::bar() is a non-template member function in a template class. If it were itself a template, SFINAE would allow the code to compile when bar() is not called. But the way you have it now, once A is instantiated with some template arguments, all of it is expected to be valid.

One solution would be:

template <typename T>
struct A {

    template <typename X>
    X* bar()
    {
        // static_assert(is_same<X, B>) if you want
        return new X(this->b);
    }

    B* b;
};

Then you'd call a.bar<B>() instead of a.bar(), and if you don't call it, it won't be instantiated and won't cause an error.

Upvotes: 1

Related Questions