Ошибка ссылки: повторяющийся символ

У меня есть 4 исходных файла, перечисленных ниже:

//a.h

#pragma once

namespace proj {
class A {} a;
} // namespace proj

//b.h

#pragma once

namespace proj {
int foo();
} // namespace proj

// b.cpp

#include "proj/a.h"
namespace proj {
int foo() {
A b = a;
return 0;
}
} // namespace proj

// c.cpp

#include "proj/a.h"#include "proj/b.h"
using namespace proj;

int main() {
A b = a;
foo();
return 0;
}

Когда я пытаюсь скомпилировать c.cpp Я получаю следующую ссылку:

duplicate symbol proj::a      in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
duplicate symbol ___odr_asan._ZN4proj1aE in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
ld: 2 duplicate symbols for architecture x86_64
collect2: error: ld returned 1 exit status

Build failed: Command failed with exit code 1.
stderr: duplicate symbol proj::a      in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
duplicate symbol ___odr_asan._ZN4proj1aE in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
ld: 2 duplicate symbols for architecture x86_64
collect2: error: ld returned 1 exit status

Я предполагаю, что это происходит потому, что b.cpp компилируется независимо от c.cpp, и поэтому препроцессор включает заголовок a.h в каждый файл индивидуально, и когда приходит время ссылаться, компоновщик находит две версии символа a.

Как мне объявить один экземпляр класса (в этом случае a) это можно использовать во всей моей программе и избежать ошибки ссылки выше?

Я использую gcc-7 (gcc-7 (Homebrew GCC 7.2.0_1) 7.2.0) в Mac OS X 10.13.3 с -std=c++17,

Система сборки

Это не должно относиться к вопросу, но, в любом случае, в том числе и в случае, если кто-то сочтет его полезным.

я использую доллар скомпилировать код (хотя это не имеет значения) с помощью следующего файла BUCK:

cxx_library(
name='a',
exported_headers=['a.h'],
visibility=['PUBLIC'],
)

cxx_library(
name='b',
exported_headers=['b.h'],
srcs = ['b.cpp'],
deps = [':a'],
visibility=['PUBLIC'],
)

cxx_binary(
name='c',
srcs = ['c.cpp'],
deps = [':a', ':b'],
)

2

Решение

Так как это помечено C ++ 17, вы можете воспользоваться новым встроенные переменные особенность языка:

namespace proj {
class A {};
inline A a;
} // namespace proj

inline переменные теперь ведут себя так же, как inline функции: ваши несколько определений a свалиться в одно.

3

Другие решения

Для предварительно C ++ 17 Стандартные решения выпуска:1

Причина ошибки компоновщика совершенно очевидна

//a.h

#pragma once

namespace proj {
class A {} a; // Declares proj::A proj::a implicitly as an instance
// everywhere a.h is included.
// Thus the linker gets confused which one to use primarly.
}

Альтернатива 1 (один единственный экземпляр):

Как мне объявить один экземпляр класса (в данном случае a), который можно использовать во всей моей программе, и избежать ошибки ссылки выше?

// a.h
#pragma once

namespace proj {
class A {};
extern A a;
}

// a.cpp
#include "a.h"
namespace proj {
proj:A a;
}

Альтернатива 2 (экземпляр на единицу перевода):

// a.h
#pragma once

namespace proj {
class A {};
}

// b.cpp
#include "a.h"
namespace { // <<< unnamed (aka anonymous) namespace
//     privately visible for translation unit
proj:A a;
}

// c.cpp
#include "a.h"
namespace {
proj:A a;
}

1)Иначе возможно @ Ответ Барри применяется лучше всего.

0

По вопросам рекламы [email protected]