使用模板参数子类型(高级案例)

时间:2017-05-26 21:28:26

标签: c++ templates circular-dependency compile-time

我有几个具有以下继承关系的类:

template <typename ID_t>
class Identifiable {
public:
    virtual ID_t unique_ID() const {
        return 0;
    }
};
template <typename DerivedName>
class SomeBase : public Identifiable<typename DerivedName::ID_t> {
public:
    virtual DerivedName & instance() = 0;
};
template <uint16_t SomeParam = 5>
class SomeDerived : public SomeBase<SomeDerived<SomeParam>> {
public:
    using ID_t = uint16_t;
    SomeDerived & instance() override {
        return *this;
    }
    ID_t unique_ID() const override {
        return SomeParam;
    }
};
int main() {    
    std::cout << "Hello, World!\n";
    SomeDerived<> instance;
    std::cout << std::to_string(instance.unique_ID()) << std::endl;
}

但是这并没有用&#34编译;在类SomeDerived&#34;中没有名为ID_t的类型。在SomeBase声明中。即使接缝很明显,有没有办法在没有这个检查的情况下强制编译?或者修改它而不将ID_t作为另一个模板参数传递?

以下是沙箱的链接:cpp.sh/57ox6

3 个答案:

答案 0 :(得分:0)

您缺少来自Identifiable的类型别名:

template <typename ID>
class Identifiable {
public:
    using ID_t = ID;
    virtual ID_t unique_ID() const {
        return 0;
    }
};

答案 1 :(得分:0)

问题是您在定义之前尝试使用SomeDerived::ID_t

你可以稍微重构一下这些课程,让它适合你。

#include <iostream>
#include <string>

template <typename ID>
class Identifiable
{
   public:
      using ID_t = ID;
      virtual ID_t unique_ID() const {
         return 0;
      }
};

template <typename DerivedName>
class SomeBase
{
   public:
      virtual DerivedName & instance() = 0;
};

template <uint16_t SomeParam = 5>
class SomeDerived : public Identifiable<uint16_t>,
                    public SomeBase<SomeDerived<SomeParam>>
{
   public:
      SomeDerived & instance() override {
         return *this;
      }
      ID_t unique_ID() const override {
         return SomeParam;
      }
};

int main()
{    
   std::cout << "Hello, World!\n";
   SomeDerived<> instance1;
   std::cout << std::to_string(instance1.unique_ID()) << std::endl;

   SomeDerived<20> instance2;
   std::cout << std::to_string(instance2.unique_ID()) << std::endl;
}

输出:

Hello, World!
5
20

答案 2 :(得分:0)

  

即使接缝很明显,有没有办法在没有这个检查的情况下强制编译?或者修复它而不将ID_t作为另一个模板参数传递?

如果没有此检查强制编译,这不是问题。你想要做的事情违反了语言的规则,就是这样。因此,它是无法编译的格式错误的代码 换句话说,在SomeBase范围内,您尝试使用未完全定义的类型(SomeDerived)。因此,您不能指望DerivedName::ID_t在那里。并且你不能期望能够告诉你的编译器 - ehy,dude,忽略C ++标准并编译它,无论它是什么

@ R.Sahu发布了his answer的有效解决方法,也许是您可以得到的最短,最有效的解决方案。
另一种选择是使用特征,如下例所示:

#include<cstdint>
#include<iostream>

template <typename T>
struct Identifiable {
    using ID_t = T;

    virtual ID_t unique_ID() const {
        return 0;
    }
};

template<typename>
struct SomeTraits;

template <typename DerivedName>
struct SomeBase : public Identifiable<typename SomeTraits<DerivedName>::ID_t> {
    virtual DerivedName & instance() = 0;
};

template <uint16_t SomeParam = 5>
struct SomeDerived;

template<uint16_t SomeParam>
struct SomeTraits<SomeDerived<SomeParam>> {
    using ID_t = uint16_t;
};

template <uint16_t SomeParam>
struct SomeDerived : public SomeBase<SomeDerived<SomeParam>> {
    using ID_t = typename SomeBase<SomeDerived<SomeParam>>::ID_t;

    SomeDerived & instance() override {
        return *this;
    }

    ID_t unique_ID() const override {
        return SomeParam;
    }
};

int main() {    
    std::cout << "Hello, World!\n";
    SomeDerived<> instance;
    std::cout << std::to_string(instance.unique_ID()) << std::endl;
}