【问题标题】:Explicit instantiation for a set of types一组类型的显式实例化
【发布时间】:2019-03-07 16:47:07
【问题描述】:

在我的代码中,通常我必须编写一个采用“类路径”类型的函数,即可以转换为boost::filesystem::path 的函数,例如

  • QString
  • std::string
  • const char *
  • 等等……

在 A.hpp 中

struct A
{
  template <typename PathLike> 
  void myFunction(PathLike path);
};

在 A.cpp 中

template <typename PathLike> 
void A::myFunction(PathLike path)
{
   boost::filesystem::Path p = convertToBoostPath(path);
   //do something...
}

//Explicit instantiations needed 
template void A::myFunction(string);  
template void A::myFunction(QString);
template void A::myFunction(char const *);
//....

问题是,如果我想在不同的函数B 中做同样的事情,我需要重新添加显式实例化。也许我采取了错误的方法。

【问题讨论】:

  • 为什么不在头文件中定义函数呢?如果需要,您可以使用 SFINAE 来约束类型。

标签: c++ templates metaprogramming


【解决方案1】:

与其编写一个接受任何PathLike 并执行实际工作的模板函数,不如编写一个接受任何PathLike 的模板函数,将其转换为boost::filesystem::Path,如图所示,然后调用一个非模板函数(其定义可以在 .cpp 中),这将完成真正的工作。

A.hpp:

class A
{
public:
  template <typename PathLike> 
  void myFunction(PathLike path);

private:
  void myFunctionImpl(boost::filesystem::Path path);
};


template <typename PathLike> 
void A::myFunction(PathLike path)
{
  myFunctionImpl(convertToBoostPath(path));
}

A.cpp:

void A::myFunctionImpl(boost::filesystem::Path path)
{
  // do something...
}

这还有一个额外的好处,即滥用接口会导致编译器错误,而不是链接器错误。

【讨论】:

    【解决方案2】:

    如何创建一个类PathLike 并使用它:

    class PathLike
    {
    public:
        explicit PathLike(const QString& path) : mPath(convertToBoostPath(path)) {}
        explicit PathLike(const std::string& path) : mPath(convertToBoostPath(path)) {}
        explicit PathLike(const char* path) : mPath(convertToBoostPath(path)) {}
        PathLike(const boost::filesystem::path& path) : mPath(path) {}
    
        const boost::filesystem::path& get() const { return mPath;}
        operator const boost::filesystem::path&() const { return mPath;}
    private:
        boost::filesystem::path mPath;
    };
    

    (我将其他构造函数显式标记为提升filesystem::path,但由您来添加/删除explicit)。

    然后:

    struct A
    {
        void myFunction(PathLike path)
        {
           boost::filesystem::path p = path;
           //do something...
        }
    };
    

    【讨论】:

      【解决方案3】:

      为一组类型显式实例化函数模板的一种方法是获取每个函数实例化的地址。例如:

      template<class... Ts>
      void instantiate_myFunction() {
          auto f = [](auto&&) { return 1; };
          auto initializer_list = { f(&A::myFunction<Ts>)...  };
          static_cast<void>(initializer_list);
      }
      
      int main() {
          instantiate_myFunction<std::string, char const*>();
      }
      

      【讨论】:

      • 您必须为每个要执行此操作的函数模板编写不同的instantiate_myFunction,对吗?据我所知,函数模板唯一能做的就是实例化它(与类模板相反,类模板可以作为模板模板参数传递),遗憾的是......
      • @MaxLanghof 没错,使用Path 类是正确的解决方案,IMO。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多