[英]C++ syntax for explicit specialization of a template function in a template class?
我的代碼適用於 VC9(Microsoft Visual C++ 2008 SP1)但不適用於 GCC 4.2(在 Mac 上):
struct tag {};
template< typename T >
struct C
{
template< typename Tag >
void f( T ); // declaration only
template<>
inline void f< tag >( T ) {} // ERROR: explicit specialization in
}; // non-namespace scope 'structC<T>'
我知道 GCC 希望我將我的顯式專業化移到課堂之外,但我無法弄清楚語法。 有任何想法嗎?
// the following is not correct syntax, what is?
template< typename T >
template<>
inline void C< T >::f< tag >( T ) {}
如果不明確專門化包含類,就無法專門化成員函數。
但是,您可以將調用轉發到部分專用類型的成員函數:
template<class T, class Tag>
struct helper {
static void f(T);
};
template<class T>
struct helper<T, tag1> {
static void f(T) {}
};
template<class T>
struct C {
// ...
template<class Tag>
void foo(T t) {
helper<T, Tag>::f(t);
}
};
GCC 很清楚,在這里。 MSVC 有一個非標准擴展,允許進行類內專業化。 然而,該標准說:
14.7.3.2:
2. 顯式特化應在模板所屬的命名空間中聲明,或者對於成員模板,應在封閉類或封閉類模板所屬的命名空間中聲明。 類模板的成員函數、成員類或靜態數據成員的顯式特化應在類模板所屬的命名空間中聲明。
此外,您不能部分專門化一個函數。 (雖然我不確定你案件的細節,但那將是最后一擊。)
你可以這樣做:
#include <iostream>
struct true_type {};
struct false_type {};
template <typename T, typename U>
struct is_same : false_type
{
static const bool value = false;
};
template <typename T>
struct is_same<T, T> : true_type
{
static const bool value = true;
};
struct tag1 {};
struct tag2 {};
template< typename T >
struct C
{
typedef T t_type;
template< typename Tag >
void foo( t_type pX)
{
foo_detail( pX, is_same<Tag, tag1>() );
}
private:
void foo_detail( t_type, const true_type& )
{
std::cout << "In tag1 version." << std::endl;
}
void foo_detail( t_type, const false_type& )
{
std::cout << "In not tag1 version." << std::endl;
}
};
int main(void)
{
C<int> c;
c.foo<tag1>(int());
c.foo<tag2>(int());
c.foo<double>(int());
}
雖然這有點難看。
遇到了這個問題。 這應該有效:
struct tag {};
template< typename T >
struct C {
template< typename Tag, typename std::enable_if<std::is_same<Tag, tag>::value, int>::type = 0>
void f( T ){
std::cout<<"tag type" <<std::endl;
}
template< typename Tag, typename std::enable_if<!std::is_same<Tag, tag>::value, int>::type = 0>
void f( T ){
std::cout<<"non tag type" <<std::endl;
}
};
我知道這可能不會讓您滿意,但我不相信您可能沒有將專業化包含在非明確專業化的結構中。
template<>
template<>
inline void C< tag1 >::foo< tag2 >( t_type ) {}
基本細節是您需要將代碼聲明放在類之外,以便只有一個聲明。 如果你把它放在一個頭文件中,聲明所有包括 c++ 源文件都可以看到,你最終會定義同一個類的多個實例。 只需將模板化函數的聲明放在頭文件中,然后將該模板化函數的聲明特化移動到您的 C++ 源文件中,一切都會好起來的,因為編譯器會根據您使用的特化類型生成正確的引用你的源代碼。
例如,您想創建一個可擴展的 Number 類,如 java 的 Number 類,以便您可以傳遞數值。 如果這是在 .h/.hpp 文件中,編譯器將知道如何生成對每個特化的引用,因為返回類型是編譯器為其生成引用的生成函數名稱的一部分。
class Number {
Int32 intVal;
double d;
float f;
Int64 longVal;
std::string strVal;
public:
template<T>
T getValue();
... other functions needed go here...
};
在您的 C++ 源文件中,您只需編寫以下內容。
template<>
Int32 Number::getValue() { return intVal; }
template<>
double Number::getValue() { return d; }
template<>
float Number::getValue() { return f; }
template<>
Int64 Number::getValue() { return longVal; }
template<>
std::string Number::getValue() { return strVal; }
現在,當您傳遞一個數字時,根據您分配給它的值類型,您可以在 getValue<>() 調用上使用適當的值類型。
雖然代碼可能不合規,但一種實用的解決方案是切換到可以正常工作的 clang。
gcc 不允許類內的成員函數完全專業化。 這是因為在功能方面它與函數重載相同。 因此,只需從特化中刪除 template<> 並使其成為函數重載即可。
來自https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 (Patrick Palka)
[...] 作為一種解決方法,而不是例如:
struct A { template<class T> struct B; template<> struct B<int> { }; // unsupported class-scope explicit specialization };
在 C++20 中可以做到:
struct A { template<class T> struct B; template<std::same_as<int> T> struct B<T> { }; };
或在 C++17 中:
struct A { template<class T, class = void> struct B; template<class T> struct B<T, std::enable_if_t<std::is_same_v<int,T>>> { }; };
嘗試這個:
template <> template<typename T> inline void C<T> :: foo<tag2>(T) {}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.