【问题标题】:Using template methods inside template classes在模板类中使用模板方法
【发布时间】:2017-10-27 23:28:18
【问题描述】:

为什么它需要 Struct1 以及如何格式化它以便我可以修改任何结构中的属性?

我有 1 个模板类用于修改 3 个包含相同属性名称的结构中的数据,它们只是碰巧使用不同的数据类型。

我正在尝试在我的模板类中使用模板方法,在各种实例化时,一切似乎都按照我对模板类的预期工作。

GenericClass<Struct1> inventory[1000];
GenericClass<Struct2> machines[1000];
GenericClass<Struct3> physicalStructures[1000];

(是的,我知道向量存在,继续玩,我包含尽可能少的代码)也就是说,当我尝试更改结构的属性之一时,我收到一个错误,指出它正在等待struct,而不是采用我手上的任何数据类型。

Main.cpp:39:28: error: no viable conversion from 'int' to 'Struct1'
inventory[0].setIdentifier(1);

我已经检查了这 3 个参考文献(以及更多参考文献),但它们似乎并没有像我在其中的任何一个中所做的那样。 How to define template function within template class in *.inl file

Template class with template function

https://isocpp.org/wiki/faq/templates

这是我的代码示例。

template <class Type>
class GenericClass
{ 
private:
  Type Identifier;
public:
  void setIdentifier(Type Param);
  Type getIdentifier();
};


/* Struct prototypes
************************/
struct Struct1
{
private:
  int Identifier;
  string Description;
  float Value;
}

struct Struct2
{
private:
  long int Identifier;
  string Description;
  float Value;
};

struct Struct3
{
private:
 string Identifier;
 string Description;
 double Value;
};


int main()
{
  GenericRecord<Struct1> inventory[1000];
  GenericRecord<Struct2> machines[1000];
  GenericRecord<Struct3> physicalStructures[1000];
  inventory[0].setIdentifier(1);
}


template <class Type>
void GenericRecord<Type>::setIdentifier(Type Param)
{
  Identifier = Param;
}
template <class Type>
Type GenericRecord<Type>::getIdentifier()
{
  return Identifier;
}

return 方法也不起作用,我预计它们都因类似原因而失败。

再次,为什么它需要 Struct1 以及如何格式化它以便我可以修改任何结构中的属性?

【问题讨论】:

  • inventory[0]GenericClass&lt;Struct1&gt; 类型,因此 inventory[0].setIdentifier() 被指定为需要 Struct1 类型的参数。您的代码正在传递intGenericClass 是一个模板类,没错,但这并不意味着 GenericClass&lt;Struct1&gt;::setIdentifier() 可以接受任何类型的参数 - 它只接受 Struct1 类型的参数。
  • 有道理,关于构建解决方案我需要了解什么?
  • 可以修改Struct1,2和3吗?
  • 这种情况下只能修改类。

标签: c++ c++11 templates


【解决方案1】:

为什么需要 Struct1

因为那是它被告知要使用的类型。

给定模板:

template<typename Type>
class GenericClass
{
private:
    Type Identifier;

public:
    void setIdentifier(Type Param);
    Type getIdentifier();
};

Struct1 (GenericClass&lt;Struct1&gt;) 类型的实例化生成以下实现:

// Just for illustration
class GenericClassStruct1
{
private:
    Struct1 Identifier;

public:
    void setIdentifier(Struct1 Param);
    Struct1 getIdentifier();
};

上述类已将所有出现的Type 替换为Struct1。现在,应该很容易理解为什么调用setIdentifier 需要Struct1 而不是int

如何格式化它以便我可以修改任何结构中的属性

有不止一种方法可以做到这一点。什么是“正确”的方式取决于您的问题的限制,但以下示例显示了一种方式。

示例

Working Example

#include <iostream>

// Declared but not defined, specializations will provide definitions
template<typename T>
struct GenericTypeTraits;

template<typename T>
class Generic
{
public:
    using IdType = typename GenericTypeTraits<T>::IdType;

    void setIdentifier(IdType id)
    {
        mType.mIdentifier = id;
    }

    IdType getIdentifier() const
    {
        return mType.mIdentifier;
    }

private:
    T mType;
};

class Type1
{
public:
    int mIdentifier;
};

template<>
struct GenericTypeTraits<Type1>
{
    using IdType = int;
};

class Type2
{
public:
    std::string mIdentifier;
};

template<>
struct GenericTypeTraits<Type2>
{
    using IdType = std::string;
};

int main()
{
    Generic<Type1> t1[5];
    t1[0].setIdentifier(3);
    std::cout << t1[0].getIdentifier() << "\n";

    Generic<Type2> t2[5];
    t2[0].setIdentifier("3");
    std::cout << t2[0].getIdentifier() << "\n";

    return 0;
}

输出

3
3

【讨论】:

    【解决方案2】:

    模板化的GenericClass 定义了一个类族。 GenericClass 的每个专业化都有自己的单一专业化 setIdentifier()。所以GenericClass&lt;Struct1&gt; 有一个接受Struct1setIdentifer(),但没有接受int(或任何其他类型)的setIdentifier()。在inventory[0].setIdentifier(1) 的用法中,inventory[0] 的类型为GenericClass&lt;Struct1&gt;,其setIdentifier() 成员函数可以接受Struct1,但不能接受int。因此出现错误消息。

    如果我理解你想要做什么(我不确定 - 只是根据你的非工作代码猜测)你需要做类似的事情;

    template<class T> class Struct
    {
       public:
          void SetIdentifier(const T &id) {Identifier = id;};
          T getIdentifier() const {return Identifier;};
        private:
           T Identifier;
           std::string Description;
           float Value;
    };
    
    template <class Type>
    class GenericClass
    { 
       private:
           Struct<Type> data;
       public:
          void setIdentifier(Type Param) {data.setIdentifier(Param);};
          Type getIdentifier() const {return data.getIdentifier();};
    };
    
    int main()
    {
          GenericClass<int> inventory[1000];
          inventory[0].setIdentifier(1);
    }
    

    【讨论】:

      【解决方案3】:
      有问题的方法中的

      Identifier 指的是GenericRecord::Identifier,它您的结构之一,而不是名为Identifier成员。同样,Type 是该结构类型,而不是其 Identifier 成员的类型。所以你的方法永远不会使用你试图包装的“属性”。

      简单的解决方案涉及属性类型的另一个模板参数:

      template<class T,class P>
      class GenericRecord {
        T wrapped;      // avoid confusing reuse of "Identifier"
      public:
        void setIdentifier(P p) {wrapped.Identifier=p;}
        P getIdentifier() const {return wrapped.Identifier;}
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-09
        相关资源
        最近更新 更多