2017-03-21 42 views
0

我试图做一个快速的实用工具类,通过构图来扩展std::vector。为此,我希望尽可能通用。声明并在一个单一的文件中实现时模板化成员函数的声明和实现

类效果很好(即main.cpp中):

的main.cpp

#include <iostream> 
#include <algorithm> 
#include <vector> 

template<typename T> 
class FVector { 

public: 

    FVector(std::vector<T> vector): _vector(vector) {} 

    template <typename unaryOperation> 
    void forEach(unaryOperation op) { 
     std::for_each(_vector.begin(),_vector.end(),op); 
    }; 

private: 

    std::vector<T> _vector; 

}; 

int main(int argc, const char * argv[]) { 

    auto printInt = [](int i){ std::cout << i << std::endl; }; 
    std::vector<int> numbers{1, 2, 3, 4, 5}; 
    FVector<int> fNumbers{numbers}; 
    fNumbers.forEach(printInt); 

    return 0; 

} 

但是,当我试图把这个类在它自己的.h和.cpp文件,编译器将不会找到构造函数或函数。

FVector.h

... 
#include <vector> 

template<typename T> 
class FVector { 

public: 

    FVector(std::vector<T>); 

    template <typename unaryOperation> 
    void forEach(unaryOperation); 

private: 

    std::vector<T> _vector; 


}; 
... 

FVector.cpp

#include "FVector.hpp" 
#include <algorithm> 

template <typename T> 
FVector<T>::FVector(std::vector<T> vector): _vector(vector) {} 

template <typename T> 
template <typename unaryOperation> 
void FVector<T>::forEach(unaryOperation op) { 
    std::for_each(_vector.begin(),_vector.end(),op); 
} 

的main.cpp

#include <iostream> 
#include "FVector.hpp" 

int main(int argc, const char * argv[]) { 

    auto printInt = [](int i){ std::cout << i << std::endl; }; 
    std::vector<int> numbers{1, 2, 3, 4, 5}; 
    FVector<int> fNumbers{numbers}; 
    fNumbers.forEach(printInt); 

    return 0; 

} 

错误

函数 'FVector ::的forEach <(拉姆达在嗒嗒/ main.cpp中:95:21)>' 具有 内部连接,但没有定义

显然,在我的语法的东西是非常错误的,但我找不到如何声明/实现这些功能。

谢谢!

+0

您需要在头文件中定义'forEach'。另见: http://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file –

+0

@VittorioRomeo所以没有办法分开声明和实现? – whitelionV

+0

是的,你可以有一个额外的“内联”头文件并包含它。这是一个非常普遍讨论的话题,请搜索它 –

回答

1

C++模板是特殊的动物:模板的每个实例都是不同的类。这意味着如果您尝试将模板类定义放入其自己的cpp中,因为该翻译单元中不需要实例,编译器将不会生成任何实例。当你尝试使用另一个翻译单元时,链接器将会抱怨,因为它找不到具体的定义。

标准声明在n4296草案(强调矿):

14模板[温度]
...
函数模板,类模板,模板变量,或静态数据成员的成员函数 类模板应在其隐式实例化的每个翻译单元中定义(14.7.1)除非 相应的专业化在某些翻译单元中被明确实例化(14.7.2);没有诊断需要 。

这就是为什么常见的用法是在头文件中的模板上写完整的定义,以确保定义将出现在每个翻译单元中。

1

现在,只有一个配方如何为FVector创建实例,但没有创建任何实例。你需要实例化一个。源文件没有办法“知道”哪些实例是需要的,因为它不包含在使用模板类的地方,那就是问题(很好,错误地阐述了,但我希望你明白了 - 基本上,当文件包括一个标题,它可以使用一切都在标题中创建一个类从一个模板,但是不知道在某些源,它甚至不知道)

这可通过写类似

完成
template class FVector<double>; 

在您的源文件的末尾专门化它超过double,然后每个forEach专业化应该存在相同。我通常有另一个文件,ClassNameSpecialization.h(在你的情况下是FVectorSpecialization.h),它只包含这些行,并包含在源文件的末尾。使添加一些专业化变得容易。

如果你想FVector是动态的,可以使用任何模板参数,因为它可能适用于代码,你需要在头文件中实现它,尽管这当然很丑。

相关问题