Specialization of a free standing template function

D

Daniel

Using Visual Studio v. 10

In test.hpp:

#ifndef TEST_HPP
#define TEST_HPP

#include <ostream>

namespace ns
{
template <class T>
void serialize(std::eek:stream& os, const T& A)
{
os << "null";
}

template <class T>
class A
{
public:
A(const T& A)
: A_(A)
{
}
void serialize(std::eek:stream& os) const
{
ns::serialize(os,A_);
}

T A_;
};
}
#endif

In test.cpp:

#include "test.hpp"

namespace ns
{
template <>
void serialize(std::eek:stream& os, const double& A)
{
os << A;
}
}

int main()
{
ns::A<double> a(10.0);
a.serialize(std::cout);

ns::B<double> a(10.0); // *
}

This compiles and links, and the output is

10

(as expected.)

However, if I include a second cpp file in the build, and move line *
to a function in that file, I get a linker error

serialize ... already defined in test.obj

Am I doing something wrong?

Thanks,
Daniel
 
G

Geoff

Using Visual Studio v. 10

In test.hpp:

#ifndef TEST_HPP
#define TEST_HPP

#include <ostream>

namespace ns
{
template <class T>
void serialize(std::eek:stream& os, const T& A)
{
os << "null";
}

template <class T>
class A
{
public:
A(const T& A)
: A_(A)
{
}
void serialize(std::eek:stream& os) const
{
ns::serialize(os,A_);
}

T A_;
};
}
#endif

In test.cpp:

#include "test.hpp"

namespace ns
{
template <>
void serialize(std::eek:stream& os, const double& A)
{
os << A;
}
}

int main()
{
ns::A<double> a(10.0);
a.serialize(std::cout);

ns::B<double> a(10.0); // *
}

This compiles and links, and the output is

10

(as expected.)

However, if I include a second cpp file in the build, and move line *
to a function in that file, I get a linker error

serialize ... already defined in test.obj

Am I doing something wrong?

Yes, you didn't post the code that's causing your problem.
Thanks,
Daniel

Show us the additional CPP file.
 
D

Daniel

Yes, you didn't post the code that's causing your problem.




Show us the additional CPP file.

Well, this will do, in test1.cpp

#include "test.hpp"

void f()
{
ns::A<double> a(10.0);
}
 
I

Ike Naar

Using Visual Studio v. 10

In test.hpp:

#ifndef TEST_HPP
#define TEST_HPP

#include <ostream>

namespace ns
{
template <class T>
void serialize(std::eek:stream& os, const T& A)
{
os << "null";
}

template <class T>
class A
{
public:
A(const T& A)
: A_(A)
{
}
void serialize(std::eek:stream& os) const
{
ns::serialize(os,A_);
}

T A_;
};
}
#endif

In test.cpp:

#include "test.hpp"

namespace ns
{
template <>
void serialize(std::eek:stream& os, const double& A)
{
os << A;
}
}

int main()
{
ns::A<double> a(10.0);
a.serialize(std::cout);

ns::B<double> a(10.0); // *

This should not compile; B is undeclared.
 
D

Daniel

This should not compile; B is undeclared.

Sorry, that should have been

ns::A<double> b(10.0); // *

Everything else copied exactly from (non-working) code :)

Daniel
 
G

Gerhard Fiedler

Daniel said:
Well, this will do, in test1.cpp

#include "test.hpp"

void f()
{
ns::A<double> a(10.0);
}

(The double spacing looks odd.)

I think you created two definitions of the serialize function.

In test1.cpp, you instantiate the template as defined in test.hpp, with
T=double. But in test.cpp, you define a specialization for T=double.

Compiling each file works, because they don't know of each other, but
the linker wants each symbol to be defined once, and here you have two
definitions for the same function ns::serialize<double>(std::eek:stream&,
double const&).

Gerhard
 
G

Geoff

Using Visual Studio v. 10

In test.hpp:

#ifndef TEST_HPP
#define TEST_HPP

#include <ostream>

I think you mean said:
namespace ns
{
template <class T>
void serialize(std::eek:stream& os, const T& A)
{
os << "null";
}

template <class T>
class A
{
public:
A(const T& A)
: A_(A)
{
}
void serialize(std::eek:stream& os) const
{
ns::serialize(os,A_);
}

T A_;
};
}
#endif

In test.cpp:

#include "test.hpp"

namespace ns
{
template <>
void serialize(std::eek:stream& os, const double& A)
{
os << A;
}
}

int main()
{
ns::A<double> a(10.0);
a.serialize(std::cout);

ns::B<double> a(10.0); // *
}

Won't compile as written. Changing it to:
ns::A<double> a(10.0); // *

yields error C2374: 'a' : redefinition; multiple initialization

Writing:
ns::A<double> b(10.0); // *

compiles and links and your test1.cpp present or not, doesn't affect
the link.
This compiles and links, and the output is

10

(as expected.)

However, if I include a second cpp file in the build, and move line *
to a function in that file, I get a linker error

Move or copy?
serialize ... already defined in test.obj

Am I doing something wrong?

Incremental link getting messed up? Clean and rebuild the project.
I tested this in VS2010 and Apple LLVM 4.2 and it links clean.
 

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

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top