什么是C ++中分离的头/源的模板专用化的鲁棒方法 [英] What is a robust way of template specialization in C++ for separated header/source

查看:111
本文介绍了什么是C ++中分离的头/源的模板专用化的鲁棒方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在中型或甚至大型复杂项目中,模板声明和定义之间的分离对于减少编译时间是有用的。



但是,程序员错误可能导致无意识的行为改变,
eg



示例:
模板专用化由于缺少声明而不可见。

  ///////////////////// file A.hpp ////////// /////////// 

#include< iostream>

template< typename T>

class A
{
public:
void foo()
{
std :: cerr< 调用通用foo< std :: endl;
}
};

//忘记以下声明导致非预期的程序行为
template<> void A < int> :: foo();

///////////////////// file A-foo-int.cpp ///////////// ////////
#includeA.hpp

模板<>
void A< int> :: foo()
{
std :: cerr<< calling< int> version of foo< std :: endl;
}

///////////////////// file main.cpp //////////// /////////
#includeA.hpp

int main(int argc,char ** argv)
{
A& int> * a = new A< int>();
a-> foo();
return 0;
}

///////////////////// Makefile /////////////// //////
CC = g ++
CPPFLAGS + = -Wall -O3
CXXFLAGS + = --std = gnu ++ 0x

all:nonrobust -template-setup

nonrobust-template-setup:main.o A-foo-int.o
$(CC)$(CPPFLAGS)main.o A-foo-int.o -o nonrobust-template-setup

clean:
rm -rf * .o nonrobust-template-setup

////////// ////////////////////////////////

问题:
是一个更稳健的设置(编译器和平台无关)
和if,它会是什么样子?

$ b

解决方案

如果没有,那么什么是测试所需函数版本的好方法? p>你不能像这样分离声明和定义:如果你在一个单独的 .cpp 文件中定义你的专用成员函数,无论你是否立即声明主模板,编译器将无法实例化它,并且链接器将抱怨未解析的引用。



通常,类模板的成员函数的定义在头文件中,除非您为相应的类模板提供了显式的实例化

 模板类X< int> ;; //你应该添加这个来使你的程序生成
//或者实例化相应的类模板
// specialization并在
//中调用foo()方法//同一翻译单元A.cpp)

一般来说,除非你面对真正的 可怕的编译时间问题,我建议你遵循常见的做法,把一切都放在一个头文件,以包括所有需要使用类模板的翻译单位:

  ///////////////////// file A.hpp //////////////// ///// 

#include< iostream>

template< typename T>

class A
{
public:
void foo()
{
std :: cerr< error:called generic foo< std :: endl;
}
};

模板<>
void A< int> :: foo()
{
std :: cerr<< calling< int> version of foo< std :: endl;
}

///////////////////// file main.cpp //////////// /////////
#includeA.hpp

int main(int argc,char ** argv)
{
A& int> * a = new A< int>();
a-> foo();
return 0;
}

如果你面对真正可怕的编译时间问题,函数定义,并将它们放入具有显式实例化的单独的翻译单元,但在C ++ 11中没有干净/简单的方法,以确保所有的专业化分别在 .cpp 文件紧接在主模板之后声明(如良好实践建议)。如果有,我想这将是如此受欢迎,你不会需要来到这里问,因为每个人面临这样的设计问题。



在某些情况下,一些奇特的宏可以帮助,但怀疑他们会比真正复杂的项目带来更多的好处。



通过引入 export 关键字,尝试在C ++ 03标准中解决这个问题,但是实现经验证明它太难以支持编译器供应商,这就是为什么 export 不再是C ++标准的一部分(因为C ++ 11)。



对于模块的更好的解决方案将使其成为C ++ 14并提供模板设计的解决方案。


In moderate-sized or even big complex projects separating template declaration and definition is useful to reduce compilation time.

However, in a complex code small programmer mistakes may lead to unnoticed behaviour change, e.g. a generic version is called instead of a specialization.

Example: Template specialization became invisible due to a missed declaration.

///////////////////// file  A.hpp /////////////////////

#include <iostream>

template <typename T>

class A 
{
public:
  void foo() 
  {
      std::cerr << " calling generic foo " << std::endl ;
  }
};

// forgetting following declaration leads to an unintended program behaviour
template <> void A< int >::foo();

///////////////////// file  A-foo-int.cpp /////////////////////
#include "A.hpp"

template <> 
void A< int >::foo()
{
  std::cerr << "calling  <int> version of foo" << std::endl;
}

///////////////////// file  main.cpp /////////////////////
#include "A.hpp"

int main(int argc , char** argv)
{
  A<int>* a = new A<int>();
  a->foo();
  return 0;
}

///////////////////// Makefile /////////////////////
CC = g++
CPPFLAGS += -Wall -O3
CXXFLAGS += --std=gnu++0x

all: nonrobust-template-setup

nonrobust-template-setup: main.o A-foo-int.o  
    $(CC)  $(CPPFLAGS) main.o A-foo-int.o  -o nonrobust-template-setup

clean: 
    rm -rf *.o nonrobust-template-setup

//////////////////////////////////////////

Question: is a more robust setup possible (compiler- and platform-independent) and if, how would it look like?

If not, what is a good way to test that a desired function version is called?

解决方案

You cannot separate declarations and definitions that way: if you relegate the definition of your specialized member functions in a separate .cpp file, no matter if you declare your specialization immediately after the primary template, the compiler won't be able to instantiate it, and the linker will complain about unresolved references.

Normally, the definition of member functions of a class template goes in a header file, unless you provide an explicit instantiation for the corresponding class templates:

template class X<int>; // You should add this to make your program build,
                       // or instantiate the corresponding class template
                       // specialization and invoke the foo() method in the
                       // same translation unit (A.cpp)

In general, unless you are facing really horrible compilation time issues, I would suggest you to follow the common practice and put everything in a header file to be included by all the translation units that need to use the class template:

///////////////////// file  A.hpp /////////////////////

#include <iostream>

template <typename T>

class A 
{
public:
    void foo() 
    {
        std::cerr << "error: called generic foo " << std::endl ;
    }
};

template <> 
void A< int >::foo()
{
    std::cerr << "calling  <int> version of foo" << std::endl;
}

///////////////////// file  main.cpp /////////////////////
#include "A.hpp"

int main(int argc , char** argv)
{
    A<int>* a = new A<int>();
    a->foo();
    return 0;
}   

If you are facing really horrible compilation time issues, then you could separate the member function definitions and put them into separate translation units with explicit instantiations, but in C++11 there is no clean/easy way to make sure that all the specializations you relegate in separate .cpp files are declared immediately after the primary template (as good practice recommends). If there were, I guess it would be so popular that you wouldn't have needed to come here and ask about it, because everybody faces such a design issue.

In some cases some fancy macros could help, but doubtfully they would bring more benefit than maintenance pain in really complex projects.

A solution to this problem was attempted in the C++03 standard by introducing the export keyword, but implementation experience proved it too hard to support for compiler vendors, which is why export is no more part of the C++ Standard (since C++11).

Hopefully, a better solution for modules will make it into C++14 and provide a solution for template design.

这篇关于什么是C ++中分离的头/源的模板专用化的鲁棒方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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