Mam plik nagłówka, który deklaruje szablonu zmiennej statycznej, a także definiuje go:Czy mogę zagwarantować, że nie zostaniesz ugryziony przez to naruszenie ODR?
/* my_header.hpp */
#ifndef MY_HEADER_HPP_
#define MY_HEADER_HPP_
#include <cstdio>
template<int n>
struct foo {
static int bar;
static void dump() { printf("%d\n", bar); }
};
template<int n>
int foo<n>::bar;
#endif // MY_HEADER_HPP_
Ten nagłówek jest włączone zarówno przez main.cpp
i wspólną bibliotekę mylib
. W szczególności, mylib_baz.hpp
zawiera właśnie ten szablon i deklaruje funkcję, która modyfikuje specjalizację szablonu.
/* mylib_baz.hpp */
#ifndef MYLIB_BAZ_HPP_
#define MYLIB_BAZ_HPP_
#include "my_header.hpp"
typedef foo<123> mylib_foo;
void init_mylib_foo();
#endif // MYLIB_BAZ_HPP_
i
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
Podczas dokonywania mylib.so
(zawierający mylib_baz.o
) symbol foo<123>::bar
jest obecny i uznane za słabe. Jednak symbolem foo<123>::bar
deklaruje również słaby w moim main.o
:
/* main.cpp */
#include "my_header.hpp"
#include "mylib_baz.hpp"
int main() {
foo<123>::bar = 456;
foo<123>::dump(); /* outputs 456 */
init_mylib_foo(); /* outputs 123 */
foo<123>::dump(); /* outputs 123 -- is this guaranteed? */
}
Wydaje się, że jestem naruszono jedną regułę rozdzielczości (foo<123>::bar
zdefiniowany zarówno w my_header.cpp
i main.cpp
). Jednak zarówno z g ++ jak i clang symbole są deklarowane jako słabe (lub unikalne), więc nie jestem przez to ukąszony - wszystkie dostępy do foo<123>::bar
modyfikują ten sam obiekt.
Pytanie 1: Czy to przypadek (może ODR działa inaczej w przypadku statycznych członków szablonów?) Lub czy w rzeczywistości gwarantuję to zachowanie przez standard?
Pytanie 2: Jak mogłem przewidzieć zachowanie, które obserwuję? To znaczy, co dokładnie sprawia, że kompilator deklaruje słaby symbol?
Myślę, że standard mówi: "To nie powinno działać", ale linker mówi "Jest OK". Naruszenie ODR to zły pomysł - kod nie będzie działał wszędzie. W języku C istnieje "wspólne rozszerzenie", które umożliwia działanie wielu definicji (zobacz [Jak używać 'extern' do współdzielenia zmiennych między plikami źródłowymi w C?] (http://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files-in-c/) - funkcja jest naprawdę właściwością linker, i istnieje spora szansa, że twoje kompilatory C i C++ dzielą się technologią linkera.) –
Zgoda! Jestem też całkiem pewien, że to nie powinno działać, ale nie mogę tak naprawdę powiedzieć, dlaczego. W moim przypadku mogłem (i powinnam!) Zadeklarować 'bar'' extern' i zdefiniować go tylko w 'mylib_baz.cpp', rozwiązując ten problem. Ale jestem naprawdę ciekawy, jak głębiej zagłębić się i zobaczyć uzasadnienie tego zachowania, które obserwuję. – FreenodeForsakeMe
"' foo <123> :: bar' zdefiniowany zarówno w my_header.cpp i main.cpp "... Co? Widzę go zdefiniowany w jednym miejscu, który nie jest jednym z wymienionych przez ciebie: 'my_header.hpp'. To jest jedna definicja. – Barry