使用“extern template”时,什么是正确的方式来专门化模板? [英] What's the right way to specialize a template when using "extern template"?

查看:173
本文介绍了使用“extern template”时,什么是正确的方式来专门化模板?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望有人可以指出正确的方法来专门化模板类中的方法,而使用extern模板类和模板类显式实例化与gnu c ++。我试着用模仿我真正的问题的最简单的例子来解决这个问题。看来,声明extern模板意味着模板实例化,当专门的方法时会导致错误。给出一个驱动程序:



main.cc

  #include A_H 
#include< iostream>

int main()
{
A< int> i
A< long> al;

std :: cout<< ai =< ai.get()< al =< al.get()<< std :: endl;

return 0;
}

以下实现A



ah

  template< typename T> 
struct A
{
int get()const;
};

extern template class A< int> ;;
extern template class A< long> ;;

a.cc

  #includeah

template< typename T>
int A< T> :: get()const
{
return 0;
}

模板<>
int A< long> :: get()const
{
return 1;
}

模板类A< int> ;;
模板类A< long> ;;

在使用g ++ 4.1.2或4.4.4编译时会收到以下错误

 %g ++ -Wall -g -D'A_H =ah'a.cc main.cc 
a.cc: 10:错误:实例化之后的'int A< T> :: get()const [with T = long int]'的专门化

如果我注释掉两个外部模板行在ah,事情编译和工作正如预期与两个编译器。我假设在没有extern模板的情况下存在一个明确的实例化,即使在C ++ 0x中也是未指定的行为,否则,C ++ 0x添加extern template的意义是什么?



如果我将A实现为:



a-hack.h

  template< typename T> 
struct A
{
int get()const;
};

template< typename T>
int A< T> :: get()const
{
return 0;
}

模板<>
inline
int A< long> :: get()const
{
return 1;
}

extern template class A< int> ;;
extern template class A< long> ;;

a-hack.cc

  #includea-hack.h

模板类A< int> ;;
模板类A< long> ;;

并再次编译,这样可以正常工作

 %g ++ -Wall -g -D'A_H =a-hack.h'a-hack.cc main.cc 
%./a.out $ b但是,在我的现实世界的例子中,这导致程序崩溃了,这是一个程序崩溃的原因。与g ++ 4.1.2(同时为g ++ 4.4.4工作)。我没有缩小崩溃的确切原因(分段错误)。它只是表现为堆栈指针在调用A> :: get()的过程中被破坏。



我意识到显式模板实例化是非标准,但是任何人都期望我上面做的工作吗?



感谢

解决方案

  extern模板类A< long> 

此行说明 A< long> 将根据编译器已经看到的定义来显式实例化



在头文件中添加您的专业化声明。

  template< typename T> struct A {/*...*/}; 
模板<> int A< long> :: get()const;
extern template class A< int> ;;
extern template class A< long> ;;

一般来说,最好尽可能多的专业化声明模板,以减少编译器对于任何特定实例化应该使用哪个声明的惊喜。






请注意, extern template 声明没有必要,如果你正在处理一个模板实体(而不是这种情况,我们必须指示编译器关于 A< long> 函数 A< long> :: get c>)。如果你想在另一个翻译单元中专门化一个函数模板,只要写 template<> 就可以了。

  template< typename T> int freeGet(){return 0; } //你甚至可以在这里安全地添加inline! 
模板<> int freeGet< long>(); // this function is not inline(14.7.3 / 12)

但是你必须有<> 。如果省略<> ,则声明变成默认实现的显式实例化( return 0 ),这可能不是你想要的!即使你添加 extern ,编译器也允许内联默认实现;如果您的代码在传递 -O2 时意外中断,您可能会意外地忽略了<> / p>

I am hoping someone can point out the correct way to specialize a method in a template class while using "extern template class" and "template class" for explicit instantiation with gnu c++. I've tried to boil down this problem with the simplest example that mimics my real problem. It appears that declaring "extern template" implies a template instantiation which causes errors when specializing methods. Given a driver program:

main.cc

#include A_H
#include <iostream>

int main()
{
    A<int> ai;
    A<long> al;

    std::cout << "ai=" << ai.get() << " al=" << al.get() << std::endl;

    return 0;
}

And the following implemntation of A

a.h

template<typename T>
struct A
{
    int get() const;
};

extern template class A<int>;
extern template class A<long>;

a.cc

#include "a.h"

template<typename T>
int A<T>::get() const
{
    return 0;
}

template<>
int A<long>::get() const
{
    return 1;
}

template class A<int>;
template class A<long>;

I receive the following error when compiling with either, g++ 4.1.2 or 4.4.4

 % g++ -Wall -g -D'A_H="a.h"' a.cc main.cc          
a.cc:10: error: specialization of 'int A<T>::get() const [with T = long int]' after instantiation
 %

If I comment out the two "extern template" lines in a.h, things compile and work as expected with both compilers. I assume depending on the existence of an explicit instantiation in the absence of "extern template" is unspecified behavior even in C++0x, otherwise, what's the point of C++0x adding "extern template"?

If I instead implement A as:

a-hack.h

template<typename T>
struct A
{
    int get() const;
};

template<typename T>
int A<T>::get() const
{
    return 0;
}

template<>
inline
int A<long>::get() const
{
    return 1;
}

extern template class A<int>;
extern template class A<long>;

a-hack.cc

#include "a-hack.h"

template class A<int>;
template class A<long>;

and compile again, this works as expected

% g++ -Wall -g -D'A_H="a-hack.h"' a-hack.cc main.cc
% ./a.out 
ai=0 al=1

However, in my real world example, this causes a program crash with g++ 4.1.2 (while working for g++ 4.4.4). I have not narrowed down the exact cause of the crash (segmentation fault). It only appears as if the stack pointer is corrupted within what would be the call to A<>::get().

I realize that explicit template instantiation is non-standard at this point, but would anyone expect what I've done above to work? If not, what is the correct way to do this?

Thanks

解决方案

extern template class A<long>;

This line says that A<long> is to be explicitly instantiated according to the definitions the compiler has already seen. When you add a specialization later, you break that meaning.

Add a declaration of your specialization to the header file.

template <typename T> struct A { /*...*/ };
template<> int A<long>::get() const;
extern template class A<int>;
extern template class A<long>;

In general, it's best to put as many specialization declarations as possible in the same header file as the primary template, to reduce surprises for the compiler about which declaration should be used for any particular instantiation.


Notice that the extern template declaration isn't necessary if you're dealing with a single template entity (as opposed to this case, where we have to instruct the compiler about both the class A<long> and the function A<long>::get()). If you want to specialize a function template in another translation unit, it suffices to write just template<>.

template<typename T> int freeGet() { return 0; }  // you can even add "inline" here safely!
template<> int freeGet<long>();  // this function is not inline (14.7.3/12)

But you must have the <> there. If you omit the <>, the declaration turns into an explicit instantiation of the default implementation (return 0), which is likely not what you wanted! Even if you add extern, the compiler is allowed to inline that default implementation; if your code unexpectedly breaks when you pass -O2, you might have accidentally omitted the <> somewhere.

这篇关于使用“extern template”时,什么是正确的方式来专门化模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆