首页 > 解决方案 > 模板争吵

问题描述

我遇到了一个问题,我创建了一个涉及模板的有点纠结的层次结构。结果是我不得不将一些代码放在错误的头文件中才能让它编译,现在编译很脆弱(如果只需要添加正确的函数,我不知道我是否可以继续编译这个项目.)

所以我正在寻找一种方法来解决这个问题,以便将代码很好地划分为适当的文件。

所以事不宜迟,代码如下:

TemplatedBase.h

template <typename T> struct TemplatedBase
{
  T value;
  
  void go();
};

派生的.h

struct Derived : public TemplatedBase<int>
{
  void hello()
  {
    printf("HI %d\n", value);
  }
};

template <typename T> void TemplatedBase<T>::go()
{
  // TemplatedBase<T> NEEDS USE OF Derived!!
  // So TemplatedBase<T>::go() is appearing here in Derived.h,
  // that's the only way I could get it to compile and it seems really
  // out of place here.
  Derived der;
  der.hello();
}

主文件

#include <stdio.h>
#include "Derived.h"

int main(int argc, const char * argv[])
{
  Derived d;
  d.go();
  return 0;
}

有没有办法可以放入TemplatedBase<T>::go()像这样的文件中TemplatedBase.cpp?唉,它似乎不起作用(你会看到 Undefined symbol:TemplatedBase<int>::go()至少在 XCode 中)。

标签: c++templates

解决方案


可以通过在 cpp 文件中使用特定类型显式实例化模板来实现:

// TemplatedBase.cpp

#include "TemplatedBase.h"
#include "Derived.h"

template <typename T>
void TemplatedBase<T>::go()
{
    // TemplatedBase<T> NEEDS USE OF Derived!!
    // So TemplatedBase<T>::go() is appearing here in Derived.h,
    // that's the only way I could get it to compile and it seems really
    // out of place here.
    Derived der;
    der.hello();
}

template struct TemplatedBase<int>; // This will make it work but now you can only use `TemplatedBase<int>`
// More instantiations go here...

但我不建议这样做,因为这会限制您可以使用的类型TemplatedBase<T>(您必须自己手动添加每种类型)。因此,请在成员函数中使用模板类型go()(这里的技巧是模板参数不会立即评估):

// TemplatedBase.h

struct Derived; // Forward declaration

template <typename T>
struct TemplatedBase
{
    T value;

    void go()
    {
        go_impl();
    }
private:
    template <typename X = Derived>
    void go_impl()
    {
        X der;
        der.hello();
    }
};
// Derived.h

#include "TemplatedBase.h"

struct Derived : public TemplatedBase<int>
{
    void hello()
    {
        printf("HI %d\n", value);
    }
};

注意:顺便说一句,从 C++20 开始,人们可以这样做:

// TemplatedBase.h

struct Derived; // Forward declaration

template <typename T>
struct TemplatedBase
{
    T value;

    void go()
    {
        [] <typename X = Derived>() {
            X d;
            d.hello();
        }();
    }
};

推荐阅读