Skip to main content
gamedev.net
🔒 Locked 🤖 Godot

Specialized Templates

Started by Axiverse Oct 13, 2006 at 12:49 AM 3 replies 550+ views
Original Post
Axiverse
Axiverse
I'm trying to do specialized templates, but am getting an error that it's compiled multiple times:

Error	1	error LNK2005: "public: static unsigned int __cdecl
Axiverse::DictionaryHasher::Hash<int>(int const &)"
(??$Hash@H@DictionaryHasher@Axiverse@@SAIABH@Z) already defined in Ethereum.obj	Main.obj	

Because it's a template, i've defined the whole thing, even the specialized template method. It seems that only the specialized template has multiple definitions, while general ones are okay.

	class DictionaryHasher
	{
	public:

	  // Methods

		template <class type>
		static unsigned int		Hash(const type& value);

	private:

	  // Constructor / Destructor

		DictionaryHasher() {};

	};

	template <>
	unsigned int DictionaryHasher::Hash<int>(const int &value)
	{
		return value;
	}

	template <class type>
	unsigned int DictionaryHasher::Hash(const type &value)
	{
		return value.Hash();
	}


should the specialized method be in a cpp file - then should i define it somehow inside the class?
Skizz
Skizz
Implementing member functions in header files outside of the class declaration will make multiple instances of the function, which makes sense as each .cpp file that includes the header will have its own version of the function. To sort this out, you need to put the function body inside the class declaration:
class DictionaryHasher{public:  // The templateed function. The body must go here since the   // type to use to instantiate the function is only known at  // the time the function is used  template <class type>  static unsigned int Hash (const type& value)   {    return value.Hash ();  }  // This is a specific instantiation of the above template   // using the int type (no need for a reference). Note that  // there is no need for the template keyword.  static unsigned int Hash (const int value)  {     return value;  }};

This works because of C++'s function overloading features. When a call to Hash is found the compiler will first look for functions that match the function signiture. If no function is found that matches, it will then try to find a template type that meets the criteria. Given that:
int i;Hash (i); // uses the predefined Hash(int) functionfloat j;Hash (j); // the compiler uses the template type <float>

The only time when you need to specify the type for the Hash function template is when the compiler can't work out what the argument type is, in which case you will need to tell the compiler by using < >. The compiler will sometimes generate a warning if it can't deduce the template parameters, sometimes the compiler will do something unexpected like use an implicit constructor (which is allowed in the C++ standard).

Skizz
CmpDev
CmpDev
Quote:

Implementing member functions in header files outside of the class declaration will make multiple instances of the function, which makes sense as each .cpp file that includes the header will have its own version of the function. To sort this out, you need to put the function body inside the class declaration:


Skizz this is news to me!!!
Axiverse your above code compiles and runs(when constructor is made public) with warning level set to 4 on visual studio.

you have guarded the header file? yes

[edit]should the specialized method be in a cpp file?
No they have to be either in the header or in a "ini" file
[edit edit]
1001 apologies Skizz:)
The specialised template should be inlined; which is what you were saying, but it does not need to be in class declaration.
template <>	inline unsigned int DictionaryHasher::Hash(const int &value)	{		return value;	}


[Edited by - CmpDev on October 13, 2006 4:54:47 AM]
Skizz
Skizz
Yes, header files should be guarded. I don't tend to include it in sample code to cut down on the noise - I usually want to make a specific point and try to make the code concentrate on that point.

The specialised function can be in a CPP file, it is, after all, just an ordinary member function. The fact there is also a templated version makes no difference.

The templated version of the function must be fully implemented in the header since the only time the function will be created is when the compiler instantiates it. When the compiler finds code like:
float f;DictionaryHasher::Hash (f);

it creates the function:
DictionaryHasher::Hash (float &value){  return value.Hash ();}

and adds it to the DictionaryHasher class, usually inlining the code. Until the compiler finds an instance of
float f;DictionaryHasher::Hash (f);

the function "DictionaryHasher::Hash (float &value)" does not exist.

Skizz
jpetrie
jpetrie
Quote:

Skizz this is news to me!!!
...
you have guarded the header file? yes


Remember, in C++, each translation unit is compiled seperately, with no knowledge of any other translation units. A translation unit can be thought of as the output from the preprocessor for a single .cpp file (in other words, the .cpp file after all macro subsitutions and includes have been processed).

Thus, an include guard only protects you from multiple definitions within a single translation unit, it does not (nor can it) protect against multiple definitions across translation units. That's why you get linker errors and not compiler errors for this problem, since it is the linker that tries to assembly the separately-compiled object files and discovers that there are multiple defintions.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.