模板参数子类型的用法(高级情况)

Usage of template parameters subtype (advanced case)

本文关键字:高级 情况 用法 参数 类型      更新时间:2023-10-16

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

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;
}

但这不会在声明行中使用"类 SomeDerived 中没有名为 ID_t 的类型"进行编译SomeBase。即使原因很明显,有没有办法在没有此检查的情况下强制编译?或者修复它而不ID_t作为另一个模板参数传递?

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

您缺少Identifiable的类型别名:

template <typename ID>
class Identifiable {
public:
    using ID_t = ID;
    virtual ID_t unique_ID() const {
        return 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

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

这不是在没有此检查的情况下强制编译的问题。你想做的事情违反了语言的规则,仅此而已。因此,它是无法编译的格式错误的代码。
换句话说,在SomeBase中,您尝试使用未完全定义的类型 ( SomeDerived (。因此,你不能指望DerivedName::ID_t在那里。而且你不能指望能够告诉你的编译器 - 呃,伙计,忽略C++标准并编译它,不管它是什么

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

#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;
}