views:

95

answers:

4

Hello :)

I'd like to package a library I'm working on as a Header-Only library to make it easier for clients to use the library (it's small and there's really no reason to make it a separate translation item). However, I cannot simply put my code in headers because such a location would violate C++'s one definition rule if a project used my library header multiple times within the same project.

How does one modify a library to make it header-only?

Billy3

EDIT: Here's example code from my 'library':

FileSystem/File.hpp:

#pragma once
#include <algorithm>
#include <string>
#include <windows.h>

namespace WindowsAPI { namespace FileSystem {

class File
{
 HANDLE handle;
public:
 File( const std::wstring& fileName,
   DWORD desiredAccess,
   DWORD shareMode,
   LPSECURITY_ATTRIBUTES securityAttributes,
   DWORD creationDisposition,
   DWORD flagsAndAttributes,
   File * const templateFile );
 File( const File& );
 ~File();
 const File& operator=( File );
 File& swap(File&);
 HANDLE getWindowsHandle() const { return handle; };
};

}} //Namespaces

FileSystem/File.cpp

#include "File.hpp"
#include "../Exception.hpp"

namespace WindowsAPI { namespace FileSystem {

File::File( const std::wstring& fileName,
   DWORD desiredAccess,
   DWORD shareMode,
   LPSECURITY_ATTRIBUTES securityAttributes,
   DWORD creationDisposition,
   DWORD flagsAndAttributes,
   File * const templateFile )
{
 handle = CreateFileW(
   fileName.c_str(),
   desiredAccess,
   shareMode,
   securityAttributes,
   creationDisposition,
   flagsAndAttributes,
   templateFile ? templateFile->handle : NULL);
 if (handle == INVALID_HANDLE_VALUE)
  WindowsApiException::ThrowFromLastError();
}

File::File( const File& other )
{
 BOOL errorCheck;
 errorCheck =
  DuplicateHandle(
   GetCurrentProcess(),
   other.handle,
   GetCurrentProcess(),
   &this->handle,
   0,
   TRUE,
   DUPLICATE_SAME_ACCESS);
 if (!errorCheck)
  WindowsApiException::ThrowFromLastError();
}

File::~File()
{
 if (!CloseHandle(handle))
  WindowsApiException::ThrowFromLastError();
}

const File& File::operator=(File other)
{
 swap(other);
 return *this;
}

File& File::swap(File& other)
{
 std::swap(handle, other.handle);
 return *this;
}

}}

template<> void std::swap<WindowsAPI::FileSystem::File>(WindowsAPI::FileSystem::File& a, WindowsAPI::FileSystem::File& b)
{
 a.swap(b);
}
A: 

Use header guards for the parts that compile in one place.

Liz Albin
Header guards only work per-translation unit.
GMan
@GMan: What more do you need?
Chris Jester-Young
Well I don't know about you; but my projects consist of more than one file.
GMan
I'm already using header guards (actually `#pragma once`) -- the issue isn't that the header is being included more than once, it's that I have more than one .cpp file in the project using the library.
Billy ONeal
@Billy: By the way, `pragma once` once is only widely supported, not standard.
GMan
Yes -- only need to support msvcc for this particular project.
Billy ONeal
+12  A: 

You can use the inline keyword:

void foo() {} // multiple definitions :(

inline void foo() {} // ok :)

inline allows the function break the one-definition rule.


If you place the definition of your member functions in your class, they become inline by default.

GMan
+1 from me. This is pretty much all inline means to modern compilers.
Charles Beattie
+3  A: 

Use header guards as Liz suggests and don't forget to put "inline" before your function methods.

ie

#ifndef MY_HEADER_H_
#define MY_HEADER_H_

inline RetType FunctionName( ParamType1 param1, ParamType2 param2 )
{
    // Function body
    return retType;
}

#endif
Goz
A: 

Also, I think you'll need to avoid any use of global variables or static variables in your header-only-library code.

Jeremy Friesner