首页 > 解决方案 > 完美转发无法与显式模板实例化指令(EIDir;又名手动实例化)链接

问题描述

问题是,当构造函数定义隐藏在实现文件 (*.cpp) 中但在主文件中显式实例化时,为什么链接器(g++,版本 7.5,Ubuntu 18.4)无法完善转发模板类的构造函数。 cp?

具体来说: fwd_machine.hpp:

#include <memory>
#include <stdexcept>

template<typename T>
struct some_type
{
 some_type(int, void*); // ld error: undefined reference to `some_type<int>::some_type(int, void*)'

 // if no EIDir, i.e., defined in the header,
 // then it works fine:
 //
 //some_type(int, void*){}
 //
 // or:
 // if explicit specialization used (with pass-through version in the header)
 // then it also works fine:
 //
 // some_type(int, void*){
 //   throw std::runtime_error("Error: only specializations whould be called...");
 // }
 // okay
};

struct factory_t
{
 template<typename some_t, typename... Args>
 decltype(auto)
 operator()(Args&&... args)
 {
   return std::make_unique<some_t>(some_t(std::forward<Args>(args)...));
 }
};

template<typename FType, typename...Fargs>
constexpr
decltype(auto) launch(FType f, Fargs&&... args)
{
 return f.template operator()<some_type<int>>(std::forward<Fargs>(args)...);
}

其中launch()函数模板运行一个通用仿函数,通过 r 值获取可变参数 args,以便可以转发它们。在这种情况下some_type(通过制作unique_ptr它)的构造函数。

但是,我需要隐藏在实现文件中的构造函数定义: fwd_machine.cpp:

#include "fwd_machine.hpp"

// if no EIDir, i.e., defined in the header,
// then it works fine...

// or:
// if explicit specialization used (with pass-through version in the header)
// then it also works fine:
//
//template<>
//some_type<int>::some_type(int, void*){} // okay

template<typename T>
some_type<T>::some_type(int, void*){} // ld error: undefined reference to `some_type<int>::some_type(int, void*)'

然后主要是对整个类使用手动实例化: main_fwd_issues.cpp:

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

// g++ -std=c++14 fwd_machine.cpp main_fwd_issues.cpp -o mfi.exe

// if no EIDir or specialization, then it works fine...
//
template class some_type<int>;

int main(void)
{
  int i{1};
  void* p{nullptr};

  auto uniq_p = launch(factory_t{}, i, p);

  std::cout<<"Finishing up...\n";
  return 0;
}

但是,如前所述,我收到链接器错误:undefined reference to `some_type<int>::some_type(int, void*)'

我发现的唯一解决方案是使用自动模板实例化(即,在标头中提供构造函数的定义);或者,使用显式特化(在头文件中定义一个不被调用的通用构造函数,并<int>在实现文件中特化)。launch()我尝试过的其他任何事情(限定构造函数的签名;没有在or中使用完美转发factory_t::operator())都失败了。

我想了解为什么链接器无法使用 的手动实例化some_type,以及是否仍有可能使用手动实例化的方法(并避免专门化)。

标签: c++c++14variadic-templatesperfect-forwardingexplicit-instantiation

解决方案


类模板@cppreference

完整的定义必须出现在类模板的显式实例化之前

当您尝试在main.cpp.

显式实例化的正确方法some_type<int>是添加

// in fwd_machine.hpp
extern template class some_type<int>;
// in fwd_machine.cpp (after the definition is complete):
template class some_type<int>;

推荐阅读