0

The code was placed in three files: test.hpp, test.cpp, another.cpp.

source code test.hpp:

#ifndef TEST_HPP_
#define TEST_HPP_

template<typename T> class Allocator
{
public:
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;
    template<typename O> struct rebind { typedef Allocator<O> other; };

    Allocator() {}
    Allocator(const Allocator& alloc) {}
    template<typename O> Allocator(const Allocator<O>& alloc) {}
    ~Allocator() {}
    pointer address(reference __x) const { return &__x; }
    const_pointer address(const_reference __x) const { return &__x; }
    void construct(pointer p, const T& value) { new ((void *)p) T(value); }
    void destroy(pointer p) { p->~T(); }

    pointer allocate(size_type n, const_pointer pHint = nullptr);// { return nullptr; }
    void deallocate(pointer p, size_type size = 0) {}
    inline size_type max_size() const { return 0; }
};
template<typename T> inline bool operator==(const Allocator<T>&, const Allocator<T>&) { return true; }
template<typename T> inline bool operator!=(const Allocator<T>&, const Allocator<T>&) { return false; }


class String : public std::basic_string<wchar_t, std::char_traits<wchar_t>, Allocator<wchar_t>>
{
    typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, Allocator<wchar_t>> string_type;
public:
    ~String() {}
    String(const wchar_t* value = L"") : string_type(value, Allocator<wchar_t>()) {}
};

#endif /* TEST_HPP_ */

source code test.cpp:

#include <iostream>
#include <string>
#include <ctime>
#include <type_traits>
#include <functional>
#include <cstddef>

#include "test.hpp"
#define MILLIS(time) (clock() - time) * 1000 / CLOCKS_PER_SEC

int main()
{
    String string = L"OK";
    return 0;
}

source code another.cpp:

#include <iostream>
#include <string>
#include <ctime>
#include <type_traits>
#include <functional>
#include <cstddef>
#include "test.hpp"


template<typename T> T* Allocator<T>::allocate(size_t n, const T* pHint)
{
    return nullptr;
}

Compiled them I got linkage error: test.cpp:(.text.startup+0x95): undefined reference to `Allocator::allocate(unsigned long, char const*)'

However, if move the code body in another.cpp into test.hpp, like this:

pointer allocate(size_type n, const_pointer pHint = nullptr) { return nullptr; }

Compilation will be successful. Since my custom Allocator::allocate() is somewhat complex, it is inconvenient that placing the code body into test.hpp header file.

Does anybody give me some suggestions? thanks.

leppie
  • 115,091
  • 17
  • 196
  • 297
Mike Zhang
  • 49
  • 3
  • My actual code can pass the compilation as debug mode and -O1 optimization release mode. Failed in -O2 and -O3. But the simplified code shown as above cannot pass compilation from -O0 ~ -O3. It's hard to understand. I ever tried adding a __attribute__((noinline)) before allocate() but no effect. I use both g++ 4.8 and 4.7, the results are same. – Mike Zhang May 15 '15 at 08:05

1 Answers1

0

The compiler cannot know where your implementation is. Since the test.hpp defines the methods, the compiler expects the implementation in test.cpp. This would also be the clean way to structure it in my opinion. However, if absolutely needed, you might get around this by individually compiling and cleverly linking the obj files in the right order. But I would consider that rather dirty.

loonytune
  • 1,775
  • 11
  • 22
  • About “Since the test.hpp defines the methods, the compiler expects the implementation in test.cpp”: I think the compiler will NOT expect the implementation locates in a cpp file with special name. I swapped the code in another.cpp and test.cpp, the compilation still fails with same error. And no right order can compile them successfully. – Mike Zhang May 15 '15 at 10:09
  • do you compile them individually to obj files and link them together manually or all at once? – loonytune May 15 '15 at 10:25