如果有這樣一個模板:
template <typename T> class Test{ public: static std::string info; };
對於以下若干種定義方式,哪些是對的(通過編譯)?
template <> string Test<int>::info("123"); template <typename T> string Test<T>::info("123"); template <typename T> string Test<T>::info; template <> string Test<int>::info; template <> string Test<int>::info(); template <typename T> string Test<T>::info();
為了不影響大家分析判斷,我把答案顏色調成比較淺的顏色,下面即是答案:
首先,說明一下三個正確的答案。
第一種形式稱之為特化定義,其作用是為模板某一特化提供其靜態成員的定義,在我們例子中,它僅僅為Test<int>類的靜態成員info提供定義。並且調用單參數構造函數初始化。
第 二種形式類似於普通類的靜態成員的定義方式,其作用是隱式地在該編譯單元為模板的所有特化提供其靜態成員的定義,在我們例子中,在首次使用 Test<int>,Test<float>,Test<char>...會隱式提供靜態成員的定義,並且調用單參 數構造函數初始化。
第三種形式和第二種形式一致,唯一不同就是采用默認構造函數初始化。
其次,說明一下三個錯誤的答案。
第一種形式,很多人都會認為是對的,認為它采用默認構造函數初始化。但編譯器會對特化定義進行特殊處理,編譯認為它是一個聲明而非定義。至於為什麼如此,應該詢問一下制定標准的人。我認為可能實現這樣的語法可能比較困難並且這個語法也比較雞肋。
第二種形式,這不成了聲明一個函數啦。
第三種形式,同第二種。
兩種正確的定義方式還有哪些其他的區別呢?
//a.cpp template <typename T> string Test<T>::info("4321"); 可以使用Test<int>::info //b.cpp template <typename T> string Test<T>::info("1234"); 也可以使用Test<int>::info
這兩個定義可以在不同的編譯單元共存,Test<int>::info的初始值是多少,這取決與靜態成員的初始化順序,所以這不是件好事。
//a.cpp template <> string Test<int>::info("123"); //b.cpp template <> string Test<int>::info("123");
而特化定義,上述方式無法通過編譯。
//a.cpp template <> string Test<int>::info("123"); //b.cpp template <typename T> string Test<T>::info("123"); 一旦使用Test<int>::info無法通編譯
上述方式無法通過編譯。
一般為了避免無法編譯,應當盡量減少使用,如下方式的定義
template <typename T> string Test<T>::info;
只有在你首次需要使用時在實現文件中給出如下特化定義即可,其他文件只要包含頭文件就能使用。
template <> string Test<int>::info("123");
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_UTILS_SINGLETON_H #define ANDROID_UTILS_SINGLETON_H #include <stdint.h> #include <sys/types.h> #include <utils/threads.h> #include <cutils/compiler.h> namespace android { // --------------------------------------------------------------------------- template <typename TYPE> class ANDROID_API Singleton { public: static TYPE& getInstance() { Mutex::Autolock _l(sLock); TYPE* instance = sInstance; if (instance == 0) { instance = new TYPE(); sInstance = instance; } return *instance; } static bool hasInstance() { Mutex::Autolock _l(sLock); return sInstance != 0; } protected: ~Singleton() { }; Singleton() { }; private: //禁止復制構造函數和賦值運算符函數,禁止類外部和內部以及友元調用 declare private,not define Singleton(const Singleton&); Singleton& operator = (const Singleton&); static Mutex sLock; static TYPE* sInstance; }; /* * use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes, * and avoid to have a copy of them in each compilation units Singleton<TYPE> * is used. * * NOTE: we use a version of Mutex ctor that takes a parameter, because * for some unknown reason using the default ctor doesn't emit the variable! 特化定義必須使用有參數的構造函數,否則認為是聲明! */ //想要使用Singleton,需要在自定義類型的實現文件中包含此宏,用以初始化類模版static變量,並顯示實例化類模版 #define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \ template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE); \ 特化定義 template<> TYPE* Singleton< TYPE >::sInstance(0); \ 特化定義 template class Singleton< TYPE >; \顯示實例化 // --------------------------------------------------------------------------- }; // namespace android