0

I was in a bad need of a list type for holding named structs with in turn an arbitrary number of members of one same type, represented by a pointer. The full project code uses Qt (if that's important).

So I wrote this:

/* 
 * This should be used with T as a pointer type.
 * Code gets really incomprehensible if T* value is used as member.
 */
template <typename T>
struct parameter_t {
    QString name;
    int count;
    T value;
};

template <typename T>
class Parameters {
private:
    typedef struct parameter_t< T > content_t; // beautification

public:
    void addParam(const QString &name, T value, int count);
private:
    std::list< content_t >* params;
};

typedef Parameters<float*> floatParameters; // beautification

Seems more than legit to me, for the actual implementation does compile error-free and stuff.

Now, from another location, I'm calling the following:

floatParameters* params = new floatParameters();
params->addParam("Ente", (float*) x, 1);

This results in compiler errors, including:

In function `...': HelperClasses.cc:(.text+0x225): undefined reference to Parameters<float*>::addParam(QString const&, float*, int)'

As you can clearly see, I'm creating floatParameters, so it's Parameters. In other words, the addParam member should translate to

void addParam(const QString &name, float* value, int count);

Why am I getting this error?

John Dibling
  • 99,718
  • 31
  • 186
  • 324
LDericher
  • 295
  • 1
  • 3
  • 12
  • (1) Why do you have so many pointers, that seems unneeded. (2) The signature in the error and the signature you typed appear to match. No problems there that I see. (3) Did you actually define the `Parameters::addParam` function anywhere? – Mooing Duck Oct 15 '12 at 16:11
  • I define addParam with the exact same signature in the corresponding source file, which compiles beautifully. – LDericher Oct 15 '12 at 16:14
  • *Edit* Which pointer exactly is unnecessary? In struct, pointer is used to get dynamic size array functionality. Just my style to avoid [] in definitions... For I got into trouble earlier when not using a pointer to a non-standard datatype attributed to a class, I used a pointer to the std::list (which is initialized in the constructor, which in turn is not shown because of missing relevance...) The exact same reason applies to the actual instanciation of the floatParameters and the call - it's (gonna be) a class member. – LDericher Oct 15 '12 at 16:19
  • `std::list< content_t >* params` is a red flag. I've _never_ had an owning pointer to a container before in my life. `floatParameters* params` seems make that _triply_ redundant. It's a pointer to a pointer to a pointer to a pointer to a bunch of doubles. – Mooing Duck Oct 15 '12 at 16:28

1 Answers1

2

Template functions should be defined in the header file, not a source file. The actual code for a template isn't built until the function is used, so the definition must be available at that point - otherwise the compiler assumes the linker will be able to find it later.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 2
    @LDericher: also see http://stackoverflow.com/questions/3749099/why-should-the-implementation-and-the-declaration-of-a-template-class-be-in-the – Mooing Duck Oct 15 '12 at 16:15
  • Okay, that's it. Thanks! Pretty embarassing actually, that I didn't find out earlier. Maybe this sort of thing happens when you've learned anything you needed so far mostly via trial-and-error :D – LDericher Oct 15 '12 at 16:34
  • @LDericher, don't feel bad. Templates look so much like regular code that it's hard to realize they need to be treated differently. I think most people make this mistake at least once. – Mark Ransom Oct 15 '12 at 16:43