Tôi có một tập tin tiêu đề mà tuyên bố một mẫu với một biến tĩnh và cũng định nghĩa nó:Tôi có được đảm bảo không bị vi phạm ODR này cắn không?
/* 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_
Tiêu đề này được bao gồm cả bởi main.cpp
và thư viện mylib
chia sẻ. Cụ thể, mylib_baz.hpp
chỉ bao gồm mẫu này và tuyên bố một hàm làm thay đổi chuyên môn của mẫu.
/* 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_
và
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
Khi tôi làm mylib.so
(chứa mylib_baz.o
), biểu tượng cho foo<123>::bar
có mặt và tuyên bố yếu. Tuy nhiên, biểu tượng cho foo<123>::bar
được khai báo yếu còn ở main.o
tôi:
/* 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? */
}
Dường như tôi đang vi phạm một quy tắc định nghĩa (foo<123>::bar
định nghĩa cả về my_header.cpp
và main.cpp
). Tuy nhiên, cả hai với g + + và clang các biểu tượng được tuyên bố yếu (hoặc duy nhất), vì vậy tôi không bị cắn bởi điều này - tất cả các truy cập để foo<123>::bar
sửa đổi cùng một đối tượng.
Câu hỏi 1: Đây có phải là sự trùng hợp ngẫu nhiên (có thể ODR hoạt động khác với thành viên tĩnh của mẫu?) Hay tôi thực tế đã đảm bảo hành vi này theo tiêu chuẩn?
Câu hỏi 2: Làm cách nào tôi có thể dự đoán hành vi mà tôi đang quan sát? Đó là, chính xác những gì làm cho trình biên dịch tuyên bố biểu tượng yếu?
Tôi nghĩ tiêu chuẩn nói "Không nên hoạt động" nhưng người liên kết của bạn nói "Không sao". Vi phạm ODR là một ý tưởng tồi - mã sẽ không hoạt động ở mọi nơi. Trong C, có một 'mở rộng phổ biến' cho phép nhiều định nghĩa hoạt động (xem [Làm cách nào để sử dụng 'extern' để chia sẻ các biến giữa các tệp nguồn trong C?] (http://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files-in-c/) - tính năng này thực sự là tài sản của linker, và có cơ hội tốt cho trình biên dịch C và C++ của bạn chia sẻ công nghệ liên kết.) –
Đồng ý! Tôi cũng khá chắc chắn điều này không nên làm việc, nhưng tôi không thể thực sự đặt ngón tay của tôi vào nó tại sao. Trong trường hợp của tôi, tôi có thể (và nên!) Đã khai báo 'bar'' extern' và chỉ định nghĩa nó trong 'mylib_baz.cpp', giải quyết vấn đề này. Nhưng tôi thực sự tò mò muốn đào sâu hơn và xem lý do đằng sau hành vi mà tôi đang quan sát. – FreenodeForsakeMe
"' foo <123> :: thanh' được định nghĩa cả trong my_header.cpp và main.cpp "... Cái gì? Tôi thấy nó được xác định ở một nơi mà không phải của những người bạn đã đề cập: 'my_header.hpp'. Đó là một định nghĩa. – Barry