   More linker PITAs
  Ok, so I think I made a similar thread a few months back, but I'm again at my wit's end with the MSVC linker. Instead of having issues with unresolved symbols, I now am getting multiply-defined ones for two small helper functions.Header, minus my standard documentation comment blocks:#pragma oncenamespace GMLib{// Rounds to the next highest power of two using bitwise shifts, bitwise ORs and an inc/decsize_t RoundToNextHighestPowerOfTwo(const size_t& value);// Rounds to the next highest power of two using bitwise shifts, bitwise ORs and an inc/dec// Does not use temporaries.void RoundToNextHighestPowerOfTwoInPlace(size_t& value);}#include "BitTricks.inl"Aforementioned .inl file:size_t GMLib::RoundToNextHighestPowerOfTwo(const size_t& value){// Make this a register, as we don't really need to store it anywhereregister size_t retval = value - 1;retval |= retval >> 1;retval |= retval >> 2;retval |= retval >> 4;retval |= retval >> 8;retval |= retval >> 16;#if GM_PLATFORM_IS64BIT// we have more bits in a size_t in 64-bit mode than in 32retval |= retval >> 32;#endif++retval;return retval;}void GMLib::RoundToNextHighestPowerOfTwoInPlace(size_t& value){value--;value |= value >> 1;value |= value >> 2;value |= value >> 4;value |= value >> 8;value |= value >> 16;#if GM_PLATFORM_IS64BIT// we have more bits in a size_t in 64-bit mode than in 32value |= value >> 32;#endif++value;}Used here, with irrelevant functions/code removed (i.e. unrelated junk)(Note that this is in an .inl file too)#include <GMLib/Functions/BitTricks.h>namespace SupernaturalThreading{template<class JobObject, class ArrayAllocator>ABPCyclicDeque<JobObject, ArrayAllocator>::ABPCyclicDeque(const DequeCapacity& capacity) : m_capacity(GMLib::RoundToNextHighestPowerOfTwo(capacity)){m_internalStorageArray = m_storageAllocator.allocate(m_capacity);}}And the unmodified entirety of main.cpp, the purported 'problem file':(it's really a unit test)#include <GMLib/Compiler.h>#include <Core/Systems/Threading/Primitives/CyclicDeque.h>int GMCDECL main(){SupernaturalThreading::ABPCyclicDeque<size_t> testDeque(4);return 0;}The errors:error LNK2005: "unsigned int __stdcall GMLib::RoundToNextHighestPowerOfTwo(unsigned int const &)" (?RoundToNextHighestPowerOfTwo@GMLib@@YGIABI@Z) already defined in main.objerror LNK2005: "void __stdcall GMLib::RoundToNextHighestPowerOfTwoInPlace(unsigned int &)" (?RoundToNextHighestPowerOfTwoInPlace@GMLib@@YGXAAI@Z) already defined in main.objNeither the header nor the inline definition files are included anywhere other than what you see here, and although I do have a pretty extensive metaprogramming library cooked up/in use, this is the only file/declaration causing problems.So anyhow, I figure there is either:- a small bug somewhere, or- I'm somehow relying on undefined compiler behavior, but my particular methodology is pretty run-of-the-mill, AFAIK.Any insight would be helpful, as I'm about ready to break something expensive :\ If it is something I'm doing, I'd love to hear the how and why and avoid any additional idiocy. I've tried moving these around, using symbol-based include guards, combining the two guard types, all with zero luck.   
  You seem to intend for your functions to be inlined, but you never actually use the inline keyword to make it so.   ;Quote:Original post by SiCraneYou seem to intend for your functions to be inlined, but you never actually use the inline keyword to make it so.Not at all, actually. I'm separating definitions from declarations, primarily. Though my understanding is that the .inl files were designed for this purpose to get around the whole "include .cpp files" black magic, they can be used whenever you wish to segregate the two in a clean fashion.... Unless you're implying that they explicitly *need* the qualifier, but these aren't the only files to do so. I'll check it and see if it solves the problem, though.   ;  There's nothing special about .inl files except, like .h and .hpp and so on, compilers generally don't consider them to be files they need to compile (contrast this with .cpp and .c files, which are compiled). Your compiler is compiling a translation unit that consists of main.cpp after the preprocessor has been run on it -- in other words, main.cpp plus all the files #include'd from it, including your header and .inl files. The compiled main.obj contains the definitions of the functions defined in your .inl file.Some other .cpp also includes those header and .inl files, and also yields a compiled .obj with the definition of those functions. When you link them together, oops, two definitions.You need to mark those functions inline -- you're basically "defining them in a header" since that's all an .inl file is. The only different between .h and .inl is purely semantic on your part. Alternatively, if you don't intend them to be inlined, put them in a .cpp file, not an .inl file, and don't go #include'ing it.Incidentally, it's not #include'ing .cpp files that's "black magic" (it doesn't work, usually, producing the same problems as you're seeing here since two translation units will define whatever is defined in that .cpp file). The black magic is what you usually have to do to make such a nasty thing work (which is usually stuff like excluding the .cpp in question from the build, which is often just a roundabout way of accomplishing exactly what header files do, etc).   ;Quote:Original post by jpetrieThere's nothing special about .inl files except, like .h and .hpp and so on, compilers generally don't consider them to be files they need to compile (contrast this with .cpp and .c files, which are compiled). Your compiler is compiling a translation unit that consists of main.cpp after the preprocessor has been run on it -- in other words, main.cpp plus all the files #include'd from it, including your header and .inl files. The compiled main.obj contains the definitions of the functions defined in your .inl file.Some other .cpp also includes those header and .inl files, and also yields a compiled .obj with the definition of those functions. When you link them together, oops, two definitions.You need to mark those functions inline -- you're basically "defining them in a header" since that's all an .inl file is. The only different between .h and .inl is purely semantic on your part.Incidentally, it's not #include'ing .cpp files that's "black magic" (it doesn't work, usually, producing the same problems as you're seeing here since two translation units will define whatever is defined in that .cpp file). The black magic is what you usually have to do to make such a nasty thing work (which is usually stuff like excluding the .cpp in question from the build, which is often just a roundabout way of accomplishing exactly what header files do, etc).Cool, that did it. Thanks, guys :)Incidentally, that initial bit was what I had in mind, though I was admittedly rather vague in the post you mentioned. I wasn't aware of the .cpp goofiness, mostly because I've just had it drilled into me that YOU JUST DON'T DO IT. END OF STORY. and as such never tried to do it.In summary; I hate the inline keyword with a passion.   ;  Yeah, don't you just hate language features that let you do what you want?   