Coop
Coop

Reputation: 309

Tool to detect C++ template issues

I recently spent some time hunting down a typo in my C++ templates. g++ did not complain about the typo, so I was wondering if there is a tool which can check for this type of problem in the future?

Here is a simplified example which demonstrates the correct compilation. I would expect a complaint about struct dummy not being defined, but it seems like the templated class goo hides that.

foo.h:

struct smart {
    int x, y, z;
};

template<typename T> class goo
{
    void barf(T* ptr){}
};

template<typename T> class foo 
{
public:
    foo(){};
private:
    goo<T> x;
};

class bar: public foo<struct dummy>
{
public:
    void do_something(struct smart& thing){}
};

foo.cpp:

#include "foo.h"

int main()
{
    bar a;
    struct smart b;
    a.do_something(b);
    return b.x+b.y+b.z;
}

Compiles successfully with g++ foo.cpp

Upvotes: 1

Views: 265

Answers (4)

Richard Corden
Richard Corden

Reputation: 21721

Attilla has nailed this; the definition of dummy is not needed and so it can remain as an incomplete type. This is an extremely useful feature of C/C++ as it helps with information hiding and also with reducing compile times.

For example:

// Afwd.h
class A;
A * getA ();
void processA(A *);
void printA (A *);


// t.cc
#include "Afwd.h"
void bar ()
{
  A * a = getA ();
  processA (a);
  printA (a);
}

Here, it's unnecessary for clients of A to see its implementation details. This also has the advantage that clients do not need to include headers that are required for the definition of A

In order to generate an error against dummy in the original example, the definition must be used in this translation unit.

Firstly, ptr needs to be used in a way which requires a complete type, for example via a dereference:

template<typename T> class goo
{
public:
    void barf(T* ptr){
      *ptr;           
    }
};

This still isn't a problem as the function barf is not called and so is not instantiated:

template<typename T> class foo 
{
public:
    foo(){
      x.barf (0);
    };
private:
    goo<T> x;
};

This code now generates an error. The constructor of bar instantiates and calls the definition of foo which instantiates and calls barf.

Upvotes: 0

Daniel
Daniel

Reputation: 31559

It's because you use struct dummy the compiler is told to auto generate a forward declaration struct if there is no such struct exiting. If you use just dummy without struct it will not do so and it will complain.

Upvotes: 2

John Dibling
John Dibling

Reputation: 101446

The compiler, set at the highest warning levels, is the best tool you have for detecting any C++ issue.

My advice to you is two fold:

1) Set your compiler warning levels at the highest level. This will catch many mistakes that lower levels may remain silent on.

2) Use a coding style that is more apt to generate compiler errors when you do something wrong. For example:

class bar: public foo<struct dummy>
{
public:
    void do_something(struct smart& thing){}
};

I honestly don't know if this code is legal or not. I strongly suspect not, but it does appear that you're declaring a new type struct dummy. The compiler accepts it, and so I'm not sure if it's legit.

You would have been well-served by doing this instead:

class bar: public foo<dummy>
{
public:
    void do_something(struct smart& thing){}
};

Now this can never be parsed as a new type declaration, and the compiler will refuse it. This would have caught your problem early.

Upvotes: 3

Attila
Attila

Reputation: 28762

If you are not using the template type parameters (which is the case in your example) the code is OK, even if the type does not exist or you are calling a function on the type in a member function that is not being called. This is in the name of C++'s if you don't use it you don't pay for it (e.g no new function is created).

Upvotes: 2

Related Questions