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 固有の拡張機能であるインラインの先行テンプレートなし)。このコードフラグメントをコンパイルする方法に光を当てることができますか?

更新:これは私が得るエラーです:

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
4

2 に答える 2

2

私はこれに混乱しています:

私はキャッチオールを使いたくない:

template class Test<int, double>

オーバーロード get(const int&) は、可能なすべての明示的なインスタンス化に対して定義されるわけではないため、コンパイラはそれをサポートしていない型に対して適合をスローするためです。

1 つの特殊化の明示性は、他の特殊化のセマンティクスには影響しません。

オーバーロードget(const int&)は単なるメンバー関数であり、他のものと同様に明示的および暗黙的な特殊化のためにインスタンス化されます。

明示的なインスタンス化は、コンパイラの速度を低下させるだけです。各インスタンス化を最大 1 回だけ処理します。暗黙的なインスタンス化の未使用部分は無視される場合がありますが、明示的にインスタンス化することで、すべてを処理するように強制されます。とにかく、単一のインスタンス化にかなりの時間がかかる可能性が高いわけではありません。

コード内のエラーを実行するには:

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 */

アップデート:

このエラーは、テンプレート以外のオーバーロードがメンバー テンプレートよりも優先されないために発生します。

残念ながら、テンプレートの親のメンバー テンプレートを明示的に特殊化することはできません。その質問の回避策は部分的に特化することですが、関数テンプレートがあるため機能しません。

回避策 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
于 2010-08-28T18:01:35.213 に答える
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 に置き換えることができます。

于 2010-08-28T18:14:09.597 に答える