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&) 不会为所有可能的显式实例定义,因此编译器会抛出不支持它的类型。

一种特化的显式性不会影响其他特化的语义。

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

更新:

该错误是由于非模板重载的优先级不高于成员模板。

不幸的是,您不能显式特化模板父级的成员模板。该问题的解决方法是部分专业化,但这不起作用,因为您有一个函数模板。

解决方法 #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 回答