2016-09-09 14 views
5

Chúng tôi đang sử dụng curiously recurring template pattern để triển khai thực đơn. Tuy nhiên, với các phiên bản Clang gần đây, chúng tôi nhận được cảnh báo -Wundefined-var-template. Bản sửa lỗi được đề xuất là thêm "tuyên bố khởi tạo rõ ràng".Làm thế nào để khắc phục một thiếu mục đích của một "tuyên bố instantiation rõ ràng" khi biên dịch một CRTP Singleton với Clang?

Tôi đã cố gắng để làm điều này, nhưng sau đó tôi nhận được lỗi về "chuyên môn hóa rõ ràng sau khi instantiation" trong đơn vị biên soạn nơi định nghĩa của singleton mẫu biến thành viên lớp.

Cấu trúc thích hợp để khắc phục vấn đề được đánh dấu bởi cảnh báo này là gì?


Giản chi tiết (nhiều logic đã được gỡ bỏ, để thực hiện một MCVE):

SingletonBase.hh:

template < class T > class SingletonBase { 
public: 
    static T * get_instance() { 
    if (! instance_) { 
     instance_ = T::create_singleton_instance(); 
    } 
    return instance_; 
    } 
private: 
    static T * instance_; 
}; 

Singleton.hh:

#include "SingletonBase.hh" 

class Singleton : public SingletonBase<Singleton> { 
    friend class SingletonBase<Singleton>; 
public: 
    int do_stuff(int v) { return v+2; } 
private: 
    static Singleton * create_singleton_instance() { 
    return new Singleton; 
    } 
}; 

Singleton.cc:

#include "Singleton.hh" 
template <> Singleton * SingletonBase<Singleton>::instance_(nullptr); 

Khi chúng tôi biên dịch bằng phiên bản tiếng kêu gần đây (3.9.0; nhưng không phải với clang 3.7), chúng tôi nhận được cảnh báo khi biên dịch các tệp khác ngoài Singleton.cc. (Với -std = C++ 11 và -Werror)

In file included from OtherFile.cc:2: 
In file included from ./Singleton.hh:2: 
./SingletonBase.hh:5:16: warning: instantiation of variable 'SingletonBase<Singleton>::instance_' required here, but no definition is available [-Wundefined-var-template] 
     if (! instance_) { 
      ^
OtherFile.cc:5:25: note: in instantiation of member function 'SingletonBase<Singleton>::get_instance' requested here 
     return Singleton::get_instance()->do_stuff(4); 
         ^
./SingletonBase.hh:11:18: note: forward declaration of template entity is here 
     static T * instance_; 
      ^

./SingletonBase.hh:5:16: note: add an explicit instantiation declaration to suppress this warning if 'SingletonBase<Singleton>::instance_' is explicitly instantiated in another translation unit 
     if (! instance_) { 
      ^
1 error generated. 

tôi đã thêm dòng sau vào cuối Singleton.hh, vì nó là những gì tôi lead to believe cú pháp khai instantiation rõ ràng nên.

extern template Singleton* SingletonBase< class Singleton >::instance_; 

Trong khi điều này khắc phục vấn đề với biên soạn OtherFile.cc, nó kết quả trong một lỗi mới khi biên soạn Singleton.cc

Singleton.cc:3:57: error: explicit specialization of 'instance_' after instantiation 
    template <> Singleton * SingletonBase<Singleton>::instance_(nullptr); 
                ^
./Singleton.hh:14:66: note: explicit instantiation first required here 
    extern template Singleton* SingletonBase< class Singleton >::instance_; 
                  ^
1 error generated. 

Những gì tôi nên làm gì ở đây để sửa chữa những cảnh báo/lỗi? Có một cú pháp thích hợp hơn cho khai báo instantiation rõ ràng mà tôi không hiểu?

+2

Nhưng tại sao oh lý do tại sao? Bạn đã tạo một thành viên tĩnh var và không khóa, do đó nó không an toàn thread. Bạn có thể đặt static đó trong 'get_instance()', phụ thuộc nếu, có thread-safe. Lớp cơ sở của bạn không đảm bảo rằng đây là một singleton, nhưng nó đòi hỏi một hàm create_instance. Tôi có thể, tại bất kỳ điểm nào, tạo ra hai trường hợp 'Singleton' w/o thậm chí chạm vào giao diện của bạn. Bạn không thể phá hủy - tái tạo nó. Bạn có thể có cơ sở và con cháu độc thân cùng một lúc. Bạn đang bị rò rỉ và không bao giờ gọi là destructor. Việc sửa chữa? Xóa các nguồn này và bắt đầu lại. (Không có vi phạm, chúng tôi có thể hướng dẫn bạn để có một thích hợp) – lorro

+0

@Iorro Hãy nhớ rằng tôi đã tách ra hầu hết các chi tiết (bao gồm cả các bit thread-an toàn) để cung cấp cho bạn một MCVE. Nếu bạn có một thực thi Singleton bạn xem xét "thực hành tốt nhất", cảm thấy tự do để liên kết nó trong một bình luận, nhưng câu hỏi ban đầu của tôi vẫn đứng. –

+0

Đây là _very_ quan trọng, tôi đề nghị bạn thêm một nhận xét về điều đó trong phần câu hỏi chính, nếu không mọi người sẽ cố gắng khắc phục những lỗi này, chứ không phải lỗi trình biên dịch. Biến thành viên -> chức năng sửa lỗi tĩnh có hoạt động cho bạn hay bạn có lý do để giữ cho nó là thành viên không? – lorro

Trả lời

1

Tôi muốn giới thiệu thực hiện này của một singleton thay vì:

template<class T> 
struct SingletonBase { 
    static T& get_instance() { 
     static T instance; 
     return instance; 
    } 
}; 

Đó là chủ đề an toàn và loại bỏ cảnh báo của bạn.

Nếu bạn muốn, bạn có thể tiếp tục của bạn create_singleton_instance:

template<class T> 
struct SingletonBase { 
    static T& get_instance() { 
     static T instance{T::create_singleton_instance()}; 
     return instance; 
    } 
}; 

Và thay đổi việc thực hiện chức năng để:

static SomeClass create_singleton_instance() { 
    return {}; 
} 
+0

.. ngoại trừ việc đó không phải là _single_ton. Bạn đã không đảm bảo một trường hợp duy nhất tại thời điểm này. – lorro

+0

Sau đó, juste làm cho hàm tạo riêng và bạn của cha mẹ. –

+0

Giải pháp được đề xuất sẽ phá vỡ điều gì đó khủng khiếp trên Microsoft Windows 8 trở xuống với Visual Studio 2015 trở xuống. Microsoft không cung cấp ["statics ma thuật"] (https://msdn.microsoft.com/en-us/library/hh567368.aspx) aka N2660 [Khởi tạo động và hủy với đồng thời] (http: //www.open- std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm). Thay đổi trình biên dịch không khắc phục được. Vấn đề là với thời gian chạy và nền tảng. Một tính năng ngôn ngữ cốt lõi của nó đã mất gần một thập kỷ để đến nơi. Microsoft đã vũ khí hóa lỗi này và sử dụng nó để buộc mọi người nâng cấp lên Windows 10 để có được nó. – jww

3

Việc sửa chữa đơn giản nhất là để xác định instance_ trong SingletonBase.hh:

template < class T > class SingletonBase { 
public: 
    static T * get_instance() { 
    if (! instance_) { 
     instance_ = T::create_singleton_instance(); 
    } 
    return instance_; 
    } 
private: 
    static T * instance_; 
}; 

template <typename T> 
T* SingletonBase<T>::instance_ = nullptr; 

Tuy nhiên, tôi không thấy điểm SingletonBase nếu bạn sẽ dựa vào T::create_singleton_instance() để tạo cá thể. Bạn cũng có thể triển khai thực hiện get_instance() trong lớp dẫn xuất.

Sử dụng CRTP để triển khai mẫu đơn có ý nghĩa chỉ khi lớp cơ sở có thể xây dựng một thể hiện của lớp dẫn xuất bằng cách sử dụng hàm tạo mặc định.

template < class T > class SingletonBase { 
    public: 
     static T& get_instance() { 
     static T instance_; 
     return instance_; 
     } 
    private: 
}; 

Đọc thêm: How to implement multithread safe singleton in C++11 without using <mutex>

Các vấn đề liên quan