使用成员模板函数显式模板实例化

发布于 2024-09-16 05:27:03 字数 1825 浏览 5 评论 0原文

我有一个带有模板成员函数的模板类。我想显式实例化该类以避免编译速度急剧下降。我正在使用 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

I have a template class with a template member function. I want to explicitly instantiate the class to avoid a drastic compilation slowdown. I am using g++ 4.1.2. I get ambiguous template specialization errors from the compiler. This the shortest code which will reproduce the problem:

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&);

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.

This code compiles in visual studio (without the inline preceeding template, which is a gcc specific extenstion). Can somebody please throw some light into how I get this code fragment to compile?

UPDATE:
This is the error I get:

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:
Thanks for the solution, it does not compile though. Specializations are not allowed inside a class. The error is:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

渔村楼浪 2024-09-23 05:27:03

我对此感到困惑:

我不想使用包罗万象的方法:

模板类Test

因为重载 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

I'm confused by this:

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.

Explicitness of one specialization does not affect the semantics of other specializations.

The overload get(const int&) is simply a member function, and it will be instantiated for explicit and implicit specializations like any other.

Explicit instantiation can only slow down the compiler. It only processes each instantiation at most once. Unused parts of an implicit instantiation may be ignored, but by explicitly instantiating, you are forcing it to handle the whole thing. Not that a single instantiation is likely to take a measurable amount of time, anyway.

To run through errors in the code:

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

Update:

The error results from the non-template overload not having priority over the member template.

Unfortunately, you cannot explicitly specialize a member template of a template parent. The workaround at that question is to partially specialize, but that won't work because you have a function template.

Workaround #2 is 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

If you can't use 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
不弃不离 2024-09-23 05:27:03
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 替换。

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");
}

This compiles just fine for me on VS2010. nullptr is c++0x btw, but you could just replace with 0/NULL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文