Separate Template Definition I wrote class Data in header. The C++Compiler compiled without errors.

I

Immortal Nephi

I wrote class Data in header. The C++ Compiler compiled without
errors. I decided to move all member functions into source code
because they are for implementation. I do not like that they are
placed in class body.

I got error message:

Linking...
Main.obj : error LNK2001: unresolved external symbol "public:
__thiscall Data<unsigned char>::eek:perator unsigned char(void)" (??B?
$Data@E@@QAEEXZ)
C:\Main.exe : fatal error LNK1120: 1 unresolved externals

Could be problem with member function cast operator. All other
member functions complied without any problems.

// Data.h
#if !defined(DATA_H )
#define DATA_H

template< typename T >
class Data {
public:
Data();
~Data();

operator unsigned char ();

private:
unsigned char x;
};

#endif // end macro !defined( DATA_H )



// Data.cpp

template< typename T >
Data< T >::Data() : x( 5 ) {}

template
Data< unsigned char >::Data();


template< typename T >
Data< T >::~Data() {}

template
Data< unsigned char >::~Data();


// Error unresolved linkage
template< typename T >
Data< T >::eek:perator unsigned char () {
return x;
}

template
Data< unsigned char >::eek:perator unsigned char ();



// main.cpp

int main() {
Data< unsigned char> data;
unsigned char x = data;

return 0;
}
 
J

Jonathan Lee

        I wrote class Data in header.  The C++ Compiler compiled without
errors.  I decided to move all member functions into source code
because they are for implementation.  I do not like that they are
placed in class body.

        I got error message:

Linking...
Main.obj : error LNK2001: unresolved external symbol "public:
__thiscall Data<unsigned char>::eek:perator unsigned char(void)" (??B?
$Data@E@@QAEEXZ)
C:\Main.exe : fatal error LNK1120: 1 unresolved externals

        Could be problem with member function cast operator.  All other
member functions complied without any problems.

GCC compiled this without a complaint, so it's legal-ish (?).
BUT you have 3 specializations declared in data.cpp without
definitions. Maybe MS is expecting the definitions.

(I actually have no idea if this is legal or not since I've
never declared a specialization and not immediately implemented
it).

--Jonathan
 
I

Immortal Nephi

GCC compiled this without a complaint, so it's legal-ish (?).
BUT you have 3 specializations declared in data.cpp without
definitions. Maybe MS is expecting the definitions.

(I actually have no idea if this is legal or not since I've
never declared a specialization and not immediately implemented
it).

Yes, I use Microsoft Visual C++ Compiler 9.0. Does anyone experience
that way?
Each member function can have more than one specification such as
char, short, long, enum, etc. I put 15 enum specifications in EACH
member functions on source code. Microsoft Visual C++ Compiler
compiled successfully without any problems, but only one problem is
the cast operator member function.
 
J

Jonathan Lee

Each member function can have more than one specification such as
char, short, long, enum, etc.

Of course, but do you actually have code that goes with these
specifications? Because the linker error is saying that MSVC
cannot find the code that goes with the function you declared.
I suspect that GCC simply falls back to the template code for
operator char(), but MS is hung up on it.

In other words, try getting rid of this line in data.cpp

template
Data< unsigned char >::eek:perator unsigned char ();

*OR* implement it

template<>
Data<unsigned char>::eek:perator unsigned char() {
return x;
}

[Of course, that doesn't explain why the constructor and
destructor are found... ]
I put 15 enum specifications in EACH
member functions on source code.

I don't know what this means, but I also can't see how it
is relevant. Except that, you know, it sounds like what
you posted isn't actually the code you're having problems
with.

--Jonathan
 
P

Paul Bibbings

Immortal Nephi said:
I wrote class Data in header. The C++ Compiler compiled without
errors. I decided to move all member functions into source code
because they are for implementation. I do not like that they are
placed in class body.

I got error message:

Linking...
Main.obj : error LNK2001: unresolved external symbol "public:
__thiscall Data<unsigned char>::eek:perator unsigned char(void)" (??B?
$Data@E@@QAEEXZ)
C:\Main.exe : fatal error LNK1120: 1 unresolved externals

Could be problem with member function cast operator. All other
member functions complied without any problems.

// Data.h
#if !defined(DATA_H )
#define DATA_H

template< typename T >
class Data {
public:
Data();
~Data();

operator unsigned char ();

private:
unsigned char x;
};

#endif // end macro !defined( DATA_H )



// Data.cpp

template< typename T >
Data< T >::Data() : x( 5 ) {}

template
Data< unsigned char >::Data();


template< typename T >
Data< T >::~Data() {}

template
Data< unsigned char >::~Data();


// Error unresolved linkage
template< typename T >
Data< T >::eek:perator unsigned char () {
return x;
}

template
Data< unsigned char >::eek:perator unsigned char ();



// main.cpp

int main() {
Data< unsigned char> data;
unsigned char x = data;

return 0;
}

Taking your code as is (adding only the relevant includes to Main.cpp
and Data.cpp), I can confirm the link failure with VC++ 2008 Express:

d:\CPPProjects\CLCPP>cl /EHsc Main.cpp Data.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

Main.cpp
Data.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

/out:Main.exe
Main.obj
Data.obj
Main.obj : error LNK2019: unresolved external symbol "public:
__thiscall Data<unsigned char>::eek:perator unsigned char(void)"
(??B?$Data@E@@QAEEXZ) referenced in function _main
Main.exe : fatal error LNK1120: 1 unresolved externals

d:\CPPProjects\CLCPP>

However, the same code seems to compile fine using gcc-4.4.3:

18:48:03 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-g++-4.4.3 -static
Main.cpp Data.cpp

18:48:49 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $

so, there appears to be some difference of opinion between the two
compilers as to whether your code should work or not.

Regards

Paul Bibbings
 
P

Paul Bibbings

Jonathan Lee said:
GCC compiled this without a complaint, so it's legal-ish (?).
BUT you have 3 specializations declared in data.cpp without
definitions. Maybe MS is expecting the definitions.

(I actually have no idea if this is legal or not since I've
never declared a specialization and not immediately implemented
it).

Is this right, what you are proposing here? If you look back at the OP's
code, what he provided were not specializations at all, but rather
*explicit instantiations*, including:

template< typename T > // primary template
Data< T >::eek:perator unsigned char() {
return x;
}

template // explicit inst. for uchar
Data< unsigned char >::eek:perator unsigned char();

I'm not that up to speed on this because I have never found myself using
explicit instantiations. Still, it is not my /expectation/ that any
further `implementation' is required here. The OP's code is, surely,
merely saying "I have this template. I shall be needing to use it on
Data< unsigned char>. Instantiate the relevant member functions (ctor,
dtor, op uchar) for me." Of course, this is necessary here, owing to the
fact that the primary definitions are themselves present in a source,
rather than a header, file. Beyond that, I'm not immediately seeing
that there is any problem with this.

Regards

Paul Bibbings
 
I

Immortal Nephi

Is this right, what you are proposing here?  If you look back at the OP's
code, what he provided were not specializations at all, but rather
*explicit instantiations*, including:

   template< typename T >               // primary template
   Data< T >::eek:perator unsigned char() {
      return x;
   }

   template                             // explicit inst. for uchar
   Data< unsigned char >::eek:perator unsigned char();

I'm not that up to speed on this because I have never found myself using
explicit instantiations. Still, it is not my /expectation/ that any
further `implementation' is required here.  The OP's code is, surely,
merely saying "I have this template. I shall be needing to use it on
Data< unsigned char>. Instantiate the relevant member functions (ctor,
dtor, op uchar) for me."  Of course, this is necessary here, owing to the
fact that the primary definitions are themselves present in a source,
rather than a header, file.  Beyond that, I'm not immediately seeing
that there is any problem with this.

Do Google and look for Q239436. It answers your question why Visual C+
+ 2008 fails to link template member function.
 
J

Jonathan Lee

Is this right, what you are proposing here?  If you look back at the OP's
code, what he provided were not specializations at all, but rather
*explicit instantiations*, including:

Ahh.. that clears things up. I didn't realize you could do that
per member function. I thought it was only for entire classes,
as in

template class Data<unsigned char>;

In that case, ignore everything I said. You're absolutely right.

--Jonathan
 
P

Paul Bibbings

GCC compiled this without a complaint, so it's legal-ish (?).
BUT you have 3 specializations declared in data.cpp without
definitions. Maybe MS is expecting the definitions.

(I actually have no idea if this is legal or not since I've
never declared a specialization and not immediately implemented
it).

--Jonathan



Is this right, what you are proposing here? If you look back at the
OP's
code, what he provided were not specializations at all, but rather
*explicit instantiations*, including:

template< typename T > // primary template
Data< T >::eek:perator unsigned char() {
return x;
}

template // explicit inst. for uchar
Data< unsigned char >::eek:perator unsigned char();

I'm not that up to speed on this because I have never found myself
using
explicit instantiations. Still, it is not my /expectation/ that any
further `implementation' is required here. The OP's code is, surely,
merely saying "I have this template. I shall be needing to use it on
Data< unsigned char>. Instantiate the relevant member functions (ctor,
dtor, op uchar) for me." Of course, this is necessary here, owing to
the
fact that the primary definitions are themselves present in a source,
rather than a header, file. Beyond that, I'm not immediately seeing
that there is any problem with this.

Regards

Paul Bibbings
 
P

Paul Bibbings

Do Google and look for Q239436.  It answers your question why Visual C+
+ 2008 fails to link template member function.

I think that there is a problem with VC over this. If you compile
only your
single file Data.cpp and then run objdump -t Data.obj, you will see
that
there is no symbol for the explicitly instantiated conversion operator
in
the table. On the other hand, even though we already have the
evidence
that it has no problem with explicit instantiations for the ctor and
dtor,
add a member function:

// Data.h
template< typename T >
class Data {
public:
// ...
unsigned char get() const;
};

// Data.cpp
template< typename T >
unsigned char Data<T>::get() const {
return x;
}

template
unsigned char Data< unsigned char >::get() const;

then compile to Data.obj again. Run objdump -t Data.obj *now and
you'll
see that Data< unsigned char >::get() is in the symbol table.

From this, it seems that VS is just not happy with honouring your
request
for an explicit instantiation of your op uchar. That's all that I
can
suggest.

Regards

Paul Bibbings
 
I

Immortal Nephi

I think that there is a problem with VC over this.  If you compile
only your
single file Data.cpp and then run objdump -t Data.obj, you will see
that
there is no symbol for the explicitly instantiated conversion operator
in
the table.  On the other hand, even though we already have the
evidence
that it has no problem with explicit instantiations for the ctor and
dtor,
add a member function:

   // Data.h
   template< typename T >
   class Data {
   public:
      // ...
      unsigned char get() const;
   };

You can add many member functions in source code you like.
   // Data.cpp
   template< typename T >
   unsigned char Data<T>::get() const {
      return x;
   }


Don't add that line below.
   template
   unsigned char Data< unsigned char >::get() const;

I successfully resolved linkage failure. I fixed template class
specification in source code. Cast operator function is working
perfectly.

Add line below.

template
class Data< unsigned char >;

...Before...add many member functions.

Review my code again.

// Data.h
#if !defined(DATA_H )
#define DATA_H


template< typename T >
class Data {
public:
Data();
~Data();

operator unsigned char ();

private:
unsigned char x;
};


#endif // end macro !defined( DATA_H )

// Data.cpp

class Data< unsigned char >;

template< typename T >
Data< T >::Data() : x( 5 ) {}

template< typename T >
Data< T >::~Data() {}

template< typename T >
Data< T >::eek:perator unsigned char () {
return x;
}


// main.cpp

int main() {
Data< unsigned char> data;
unsigned char x = data;

return 0;
}

MS Visual C++ Compiler compiled successfully without errors.
 
P

Paul Bibbings

You can add many member functions in source code you like.


Don't add that line below.


        I successfully resolved linkage failure.  I fixed template class
specification in source code.  Cast operator function is working
perfectly.

        Add line below.

template
class Data< unsigned char >;

        ...Before...add many member functions.

Review my code again.

// Data.h
#if !defined(DATA_H )
#define DATA_H

template< typename T >
class Data {
public:
        Data();
        ~Data();

        operator unsigned char ();

private:
        unsigned char x;

};

#endif // end macro !defined( DATA_H )

// Data.cpp

class Data< unsigned char >;

template< typename T >
Data< T >::Data() : x( 5 ) {}

template< typename T >
Data< T >::~Data() {}

template< typename T >
Data< T >::eek:perator unsigned char () {
        return x;

}

// main.cpp

int main() {
        Data< unsigned char> data;
        unsigned char x = data;

        return 0;

}

        MS Visual C++ Compiler compiled successfully without errors.

I have tried this using VC++ 2008 (with cl /EHsc Main.cpp Data.cpp)
and it
doesn't work. I get, as I would expect:

d:\CPPProjects\CLCPP>cl /EHsc Main.cpp Data.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version
15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

Main.cpp
Data.cpp
Data.cpp(5) : error C2906: 'Data<unsigned char>' : explicit
specialization requires 'template <>'

If I change the first code line of your Data.cpp to:

template // explicit instantiation
class Data< unsigned char >;

then VC++ is apparently happy with it. (The omission of `template'
may
have been an oversight on your part when you posted your code.)

However, I am not sure that this *should* work. To me, the explicit
instantiation is then the wrong side of the template definitions, and
certainly gcc-4.4.3 fails your code, thus corrected, with an undefined
reference on *all* of the member functions of your Data class. If,
then,
you move the explicit instantiation to the *end* of your Data.cpp,
after
the definitions, then it works for both gcc and VC.

However, this does not alter the fact that your first attempt -
providing an explicit instantiation for each of the members
individually -
should have been accepted by VC also. In effect, all that you are
doing
here with your second attempt is doing in one line what you had
previously
requested be done in 3. I am beginning to think that there is a bug
here
in VC.

Regards

Paul Bibbings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top