Ошибка ссылки при использовании встроенной математической библиотеки в сочетании с предварительно скомпилированным заголовочным файлом

Сегодня я столкнулся с довольно странной проблемой. У меня есть математическая библиотека, оптимизированная для SSE, поэтому почти весь функционал объявлен как встроенный. Для упрощения я объясню проблему только с помощью одного класса, Vector3:

Vector3 объявлен в Vector3.h примерно так:

#ifndef VIRTUS_VECTOR3_H
#define VIRTUS_VECTOR3_H

#ifndef VEC3INLINE
  #if(_DEBUG)
    #define VEC3INLINE inline
  #else
    #define VEC3INLINE __forceinline
  #endif
#endif

namespace Virtus {

struct Vector3
{
  union
  {
    struct { f32 x,y,z; };
    f32 v[3];
  };

  Vector3(void);
  Vector3(const Vector3& rhs);
  Vector3(f32 xx, f32 yy, f32 zz);

  VEC3INLINE Vector3& operator=(const Vector3& rhs);

  VEC3INLINE Vector3 operator+(f32 rhs) const;
  VEC3INLINE Vector3 operator-(f32 rhs) const;
  VEC3INLINE Vector3 operator*(f32 rhs) const;
  VEC3INLINE Vector3 operator/(f32 rhs) const;
  VEC3INLINE Vector3& operator+=(f32 rhs);
  VEC3INLINE Vector3& operator-=(f32 rhs);
...

#include "vector3.inl"
#endif

В vector3.inl я продолжаю определять все функции

namespace Virtus {

Vector3::Vector3(void)
  : x(0.0f), y(0.0f), z(0.0f)
{
}

Vector3::Vector3(const Vector3& rhs)
  : x(rhs.x), y(rhs.y), z(rhs.z)
{
}

Vector3::Vector3(f32 xx, f32 yy, f32 zz)
  : x(xx), y(yy), z(zz)
{
    }

VEC3INLINE Vector3& Vector3::operator=(const Vector3& rhs)
{
  memcpy(v, rhs.v, sizeof(v));
  return *this;
}

    ...

Затем я включаю все свои математические объекты в файл с именем math.h.

#ifndef VIRTUS_MATH_H
#define VIRTUS_MATH_H

#include "vector2.h"
#include "vector3.h"
#include "vector4.h"
#include "matrix4.h"
#include "primesearch.h"

namespace Virtus
{
  class MathException
  {
  public:
    enum ErrorCode
    {
      PRIME_SEARCH_INVALID_ELEMENTS,
      PRIME_SEARCH_UNSUFFNUM_PRIMES
    };

    MathException(ErrorCode code) : m_Error(code) {}
    ErrorCode What(void) const { return m_Error; }

  private:
    ErrorCode m_Error;
  };
} // namespace virtus

#endif // Include Guard

и math.h включен в мой предварительно скомпилированный заголовочный файл (precompiled.h, он же stdafx.h)

Я использую Visual Studio 2008, которая должна автоматически исключать файлы .inl из процесса сборки.

Это ошибка компоновщика, которую я получаю:

Ошибка 1 ошибка LNK2005: "public: __thiscall Virtus::Vector3::Vector3(void)" (??0Vector3@Virtus@@QAE@XZ), уже определенный в precompiled.obj main.obj Virtus

Я пытался исправить это практически всеми мыслимыми способами, например, исключая все inl-файлы из сборки вручную; не включая math.h в предварительно скомпилированный файл, а только там, где он мне нужен (в этом случае я получаю аналогичную уже определенную ошибку компоновщика); переход от расширения inl к расширению cpp и так далее. Единственный способ исправить это — использовать #pragma один раз вместо включения защиты. Так что мое лучшее предположение на данный момент состоит в том, что это как-то связано с комбинацией предварительно скомпилированных файлов заголовков и включения защиты, но я не совсем уверен, как это исправить.

Помощь будет высоко оценена!


person Millianz    schedule 24.06.2011    source источник


Ответы (1)


Каждое из определений внутри vector3.inl должно быть явно определено с помощью inline.

person ildjarn    schedule 24.06.2011
comment
Плохо, что я не включил определение встроенной функции в примеры из vector3.inl. Я отредактировал свой пост, чтобы отразить использование ключевого слова inline в файле реализации. - person Millianz; 25.06.2011
comment
@Millianz: inline относится к определению, а не к объявлению - поэтому я сказал изменить определения внутри vector3.inl. ;-] - person ildjarn; 25.06.2011
comment
Спасибо, что указали на это, теперь я вижу более ясно. Есть проблема с моей реализацией, с которой, похоже, может справиться компилятор Microsoft. Это не было причиной, по которой ссылка не устанавливалась, хотя, как вы указали, это было неправильно. Основная проблема заключалась в реализации не встроенных функций в файле inl, который был включен в заголовок. Это вызвало множество определений. В конце концов, это было действительно очевидно :P Иногда в лесу не видно дерева :) Спасибо за помощь - person Millianz; 25.06.2011