C ++模板类型cheking

时间:2016-06-27 19:49:25

标签: c++ templates types

class Nation{
      private :
        string  continent;
        string  pays;
        string  capital;
        long    superficie;
        long    population;

      public :
        static const string CONTINENT ;
        static const string PAYS      ;
        static const string CAPITAL   ;
        static const long   SUPERFICIE;
        static const long   POPULATION;
    .....
    const string Nation::CONTINENT ="1";
    const string Nation::PAYS      ="2";
    const string Nation::CAPITAL   ="3";
    const long   Nation::SUPERFICIE= 4;
    const long   Nation::POPULATION= 5;
    ....
        template <class T>
        void Nation::setField(T fieldType, T valeur){
            if(typeid(fieldType).name()==typeid(this->CAPITAL).name()){
                if (fieldType==this->PAYS     ) this->pays      = valeur;
                if (fieldType==this->CAPITAL  ) this->capital   = valeur;
                if (fieldType==this->CONTINENT) this->continent = valeur;
            }
            else if(typeid(fieldType).name()==typeid(this->SUPERFICIE).name()){
                if (fieldType==this->SUPERFICIE) this->superficie = valeur;
                if (fieldType==this->POPULATION) this->population = valeur;
            }
        }
    .......
    }

编译器说有一些错误:"[Error] no match for 'operator==' (operand types are 'std::basic_string<char>' and 'const long int')" 在这一行:

if (fieldType==this->SUPERFICIE) this->superficie = valeur;

编译错误不是运行时间。

调用该函数:

country1.setField(Nation::PAYS, "CANADA");
country1.setField(Nation::POPULATION, 12345678);

我很高兴感谢你。

4 个答案:

答案 0 :(得分:3)

这是(问题)模板,它们在编译时得到评估,因此像if(typeid(fieldType).name()==typeid(this->CAPITAL).name())这样的条件不会保护&#34;随后对模板的评估。

当您致电

时会发生什么
country1.setField(Nation::PAYS, "CANADA");

T已解决(在编译时)const char*,因此fieldType的类型将为const char*。然后,在这个分支

else if(typeid(fieldType).name()==typeid(this->SUPERFICIE).name()){
                if (fieldType==this->SUPERFICIE) this->superficie = valeur;
                if (fieldType==this->POPULATION) this->population = valeur;
            }

即使这不会执行,因为fieldTypeSUPERFICIE的类型不同,但在编译时不知道。基本上,您要将fieldTypeconst char*}与SUPERFICIElong)进行比较,并且没有隐式比较器函数来执行该转换,并且所以编译器会抛出错误。

你能做什么:

  • 专门针对setFieldlong
  • const char*
  • 使用2个重载函数(const char*long)代替模板alltogether

答案 1 :(得分:2)

模板不能以这种方式工作,你不能突然“改变”从if到另一个的类型。你能做的就是超载:

void Nation::setField(string fieldType, string valeur){
                if (fieldType==this->PAYS     ) this->pays      = valeur;
                if (fieldType==this->CAPITAL  ) this->capital   = valeur;
                if (fieldType==this->CONTINENT) this->continent = valeur;
            }

void Nation::setField(long fieldType, long valeur){
                if (fieldType==this->SUPERFICIE) this->superficie = valeur;
                if (fieldType==this->POPULATION) this->population = valeur;
            }

进一步评论:

  • 将字符串函数参数作为const引用
  • 尝试使用switch()代替if()(适用于第二种情况)
  • 根据您的使用情况,您可能希望单独将字符串转换为字段索引。如果你两次访问同一个字段,你肯定想要这样做。

答案 2 :(得分:1)

首先,我会将你的常量声明为枚举,并使你的函数的第一个参数成为类型。无需使指示符与您尝试存储的字段的类型相同。

其次,正如其他人所指出的,重载功能更适合您尝试使用的功能。模板实际上在编译之前在幕后创建重载函数,然后编译它们。因此,您编写的内容实际上看起来更像是编译器:

void Nation::setField(int fieldType, int valeur){
    if(typeid(fieldType).name()==typeid(this->CAPITAL).name()){
        if (fieldType==this->PAYS     ) this->pays      = valeur;
        if (fieldType==this->CAPITAL  ) this->capital   = valeur;
        if (fieldType==this->CONTINENT) this->continent = valeur;
    }
    else if(typeid(fieldType).name()==typeid(this->SUPERFICIE).name()){
        if (fieldType==this->SUPERFICIE) this->superficie = valeur;
        if (fieldType==this->POPULATION) this->population = valeur;
    }
}

void Nation::setField(string fieldType, string valeur){
    if(typeid(fieldType).name()==typeid(this->CAPITAL).name()){
        if (fieldType==this->PAYS     ) this->pays      = valeur;
        if (fieldType==this->CAPITAL  ) this->capital   = valeur;
        if (fieldType==this->CONTINENT) this->continent = valeur;
    }
    else if(typeid(fieldType).name()==typeid(this->SUPERFICIE).name()){
        if (fieldType==this->SUPERFICIE) this->superficie = valeur;
        if (fieldType==this->POPULATION) this->population = valeur;
    }
}

仔细观察,您可以看到编译器将如何抱怨。

因此,使用枚举进一步修改代码将如下所示:

...
enum FieldType {CONTINENT, PAYS, CAPITAL, SUPERFICIE, POPULATION};

void Nation::setField(FieldType fieldType, string valeur){
     if (fieldType==FieldType::PAYS)     this->pays      = valeur;
     if (fieldType==FieldType::CAPITAL)  this->capital   = valeur;
     if (fieldType==FieldType::CONTINENT)this->continent = valeur;
}

void Nation::setField(FieldType fieldType, long valeur){
    if (fieldType==FieldType::SUPERFICIE) this->superficie = valeur;
    if (fieldType==FieldType::POPULATION) this->population = valeur;
}
...

编译器将根据传递给valeur参数的值的类型自动决定调用哪个函数。从那里,您所要做的就是决定存储价值的位置。

答案 3 :(得分:1)

Meta:正如其他已经给出解决问题的解决方案一样,我认为用另一种观点来看待这个问题对于OP和其他将在稍后看这个问题的人来说都是有益的。

如果您只关心调用方法的语义,那么您可以这样做,这不仅更快,而且更灵活:

struct Nation {
private :
    string  continent;
    string  pays;
    string  capital;
    long    superficie;
    long    population;

public :
    static const constexpr auto CONTINENT = &Nation::continent;
    static const constexpr auto PAYS = &Nation::pays;
    static const constexpr auto CAPITAL = &Nation::capital;
    static const constexpr auto SUPERFICIE = &Nation::superficie;
    static const constexpr auto POPULATION = &Nation::population;
};

现在,实现setField功能变得微不足道。您需要的唯一实现是:

template<typename Member, typename V>
void setField(Member m, V&& value) {
    this->*m = std::forward<V>(value);
}

然后,你可以这样称呼你的功能:

Nation country1;

country1.setField(Nation::PAYS, "CANADA");
country1.setField(Nation::POPULATION, 12345678);

如果编译时反射可用,甚至可以自动生成指针。

编辑:以下是对此处使用的概念的快速解释。

我与&&std::forward一起使用的技术称为完美转发。这用于以通用方式移动语义或复制语义。您可以查看转发参考通用参考

有趣的是使用成员指针。指向成员的指针就像一个类成员的别名。换句话说,您可以使用别名,而不是直接使用类的成员;你可以使用指向成员的指针。

当与特定实例一起使用时,指向成员的指针就像访问成员指向的成员一样。它们与运算符.*或运算符->*一起使用。操作符的左侧是对象,右侧是指向成员的指针。

在我的示例中,CONTINENTPAYS和其他人指向相关成员。

您可以在此处详细了解有关poiter成员的信息:Pointers_to_data_members此处:operator_member_access