2010-08-28 199 views
4

我有一個帶模板成員函數的模板類。我想明確地實例化這個類,以避免劇烈的編譯放緩。我正在使用g ++ 4.1.2。我從編譯器中得到不明確的模板特化錯誤。這將重現該問題在最短的代碼:使用成員模板函數顯式模板實例化

template <class T, class S > 
class Test 
{ 
public: 
template< typename T1 > 
void* get(const T1&); 
void* get(const int&); //Specialization of the above 
}; 

typedef Test<int, double> foo; 

//instantiate 
inline template class Test<int, double>; 
template void* foo::get(int const&); 

我不想用一個包羅萬象:

template class Test<int, double> 

因爲超載GET(const int的&)將不被定義所有可能的顯式實例化,因此編譯器會拋出不支持它的類型。

這段代碼在visual studio中編譯(沒有內聯前面的模板,這是一個gcc特定的擴展)。有人可以告訴我如何讓這段代碼片段編譯?

UPDATE: 這是我的錯誤:

g++ -c -o template.o template.cpp 
template.cpp:14: error: ambiguous template specialization ‘get<>’ for ‘void* Test<int, double>::get(const int&)’ 
template.cpp:7: error: candidates are: void* Test<T, S>::get(const int&) [with T = int, S = double] 
template.cpp:6: error:     template<class T1> void* Test::get(const T1&) [with T1 = T1, T = int, S = double] 

UPDATE2: 感謝您的解決方案,它不雖然編譯。專業課不允許在課堂上進行。錯誤是:

g++ -c -o template.o template.cpp 
template.cpp:7: error: explicit specialization in non-namespace scope ‘class Test<T, S>’ 
template.cpp:7: error: enclosing class templates are not explicitly specialized 
template.cpp:8: error: ‘get’ is not a template function 
template.cpp: In instantiation of ‘void* Test<T, S>::get(const T1&) [with T1 = int, T = int, S = double]’: 
template.cpp:15: instantiated from here 
template.cpp:15: error: explicit instantiation of ‘void* Test<T, S>::get(const T1&) [with T1 = int, T = int, S = double]’ but no definition available 
make: *** [template.o] Error 1 
+0

'foo'是爲了'Test'嗎?你能發佈實際的錯誤和它所指的行嗎? – 2010-08-28 07:14:09

+0

我鍵入foo以方便打字。實際的錯誤是: g ++ -c -o template.o template.cpp template.cpp:14:error:ambiguous template specialization'get <>'for'void * Test :: get(const int&)' template .cpp:7:error:candidate are:void * Test :: get(const int&)[with T = int,S = double] template.cpp:6:error:template void * Test :: get(const T1&)[與T1 = T1,T = INT,S =雙倍] – Venkatesan 2010-08-28 07:23:48

+0

糟糕,我沒有看到'typedef',對不起。 – 2010-08-28 07:26:06

回答

2

我很困惑這個:

I don't want to use a catch-all:

template class Test<int, double> 

because the overload get(const int&) will not be defined for all possible explicit instantiations and hence the compiler will throw a fit for types which dont support it.

一個明晰的專業化,不影響其他專業化的語義。

重載get(const int&)只是一個成員函數,它將被實例化爲顯式和隱式的特化,就像任何其他。

顯式實例化只能減慢編譯器。它只處理每個實例最多一次。隱式實例化中未使用的部分可能會被忽略,但通過明確實例化,你迫使它處理整個事情。不是說一個實例化可能會花費可觀的時間。

要通過錯誤代碼運行:

template <class T, class S > // arguments unused 
class Test 
{ 
public: 
template< typename T1 > 
void* get(const T1&); 
void* get(const int&); // overload of the above 
}; 

typedef Test<int, double> foo; 

// illegal to instantiate a template before its members are defined 

inline template class Test<int, double>; // "inline template" is meaningless 
template void* foo::get(int const&); // typedef name "foo" cannot be used here 
/*^illegal to explicitly instantiate a member of an already explicitly 
    instantiated template */ 

更新:

來自成員模板沒有優先非模板超載的錯誤結果。

不幸的是,你cannot explicitly specialize模板父母的成員模板。在這個問題的解決方法是部分專門化,但這不會工作,因爲你有一個函數模板。

解決方法#2是SFINAE。

#include <boost/enable_if.hpp> 
#include <boost/type_traits.hpp> 

template< typename T1 > 
boost::disable_if< boost::is_same<T1,int>, void* >::type 
    get(const T1&); // "turn off" declaration if in conflict 

void* get(const int&); // unambiguous overload of the above 

如果你不能使用Boost,

template< class T > 
struct disable_if_int { typedef void *type; }; 

template<> 
struct disable_if_int<int> {}; 

...

template< typename T1 > 
disable_if_int<T1>::type get(const T1&); 

void* get(const int&); // unambiguous overload of the above 
+0

在gcc中,如果使用內聯實例化,則不會對成員函數進行初始化,並且可以根據需要進行操作。如果在實例化時不使用「內聯」,則模板的所有成員都將被實例化。參考:http://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html 對不起,不好的措辭,我想能夠通過使用內聯實例化每個必要的成員,並嘗試這樣做時得到錯誤。 – Venkatesan 2010-08-30 06:39:48

+0

@Venkatesan:「每個必要的成員」?根據您鏈接的頁面,沒有成員被實例化。 – Potatoswatter 2010-08-30 06:54:14

0
template <class T, class S > 
class Test 
{ 
public: 
template< typename T1 > 
void* get(const T1&) { return nullptr; } 

template <> 
void* get<int>(const int&) { return nullptr; } //Specialization of the above 
}; 

typedef Test<int, double> foo; 

int main() { 
    foo lols; 
    void* innit = lols.get(1); 
    void* bruv = lols.get("yocakes"); 
} 

這編譯就好了,我在VS2010。 nullptr是C++ 0x順便說一句,但你可以用0/NULL替換。

+0

14.7.3/2:「對於成員模板,應聲明一個顯式的特殊化,在其封閉類或封閉類模板所屬的名稱空間中。」 此外,您完全刪除了顯式實例,這有助於迴避問題。 – Potatoswatter 2010-08-28 18:49:24