Ho un file di intestazione che dichiara un modello con una variabile statica e definisce inoltre:Sono sicuro di non essere morso da questa violazione 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_
Questa intestazione è incluso sia dal main.cpp
e una biblioteca mylib
condiviso. In particolare, mylib_baz.hpp
include solo questo modello e dichiara una funzione che modifica una specializzazione del modello.
/* 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_
e
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
quando faccio mylib.so
(contenente mylib_baz.o
), il simbolo per foo<123>::bar
è presente e ha dichiarato debole. Tuttavia, il simbolo per foo<123>::bar
è dichiarato debole anche nel mio 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? */
}
Sembra che sto violando una regola di definizione (foo<123>::bar
definito sia in my_header.cpp
e main.cpp
). Tuttavia, sia con g ++ che clang i simboli sono dichiarati deboli (o unici), quindi non mi viene morso da questo: tutti gli accessi a foo<123>::bar
modificano lo stesso oggetto.
Domanda 1: Si tratta di una coincidenza (forse l'ODR funziona in modo diverso per i membri statici dei modelli?) O sono effettivamente garantito questo comportamento dallo standard?
Domanda 2: Come avrei potuto prevedere il comportamento che sto osservando? Cioè, cosa rende il compilatore dichiaratamente debole?
Penso che lo standard dica "Non dovrebbe funzionare" ma il tuo linker dice "Va tutto bene". Violare l'ODR è una cattiva idea - il codice non funzionerà ovunque. In C, esiste una "estensione comune" che consente il funzionamento di più definizioni (si veda [Come utilizzare 'extern' per condividere le variabili tra i file di origine in C?] (http://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files-in-c/) - la funzionalità è davvero una proprietà del linker, e c'è una buona possibilità che i compilatori C e C++ condividano la tecnologia del linker.) –
Concordato! Sono anche abbastanza sicuro che questo non dovrebbe funzionare, ma non riesco davvero a capirlo perché. Nel mio caso, potrei (e dovrei!) Dichiarare 'bar' extern' e solo definirlo in' mylib_baz.cpp', risolvendo questo problema. Ma sono davvero curioso di scavare più a fondo e vedere la logica dietro il comportamento che sto osservando. – FreenodeForsakeMe
"' foo <123> :: bar' definito sia in my_header.cpp che in main.cpp "... Cosa? Lo vedo definito in un posto che non è nessuno di quelli che hai citato: 'my_header.hpp'. Questa è una definizione. – Barry