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);
我很高兴感谢你。
答案 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;
}
即使这不会执行,因为fieldType
与SUPERFICIE
的类型不同,但在编译时不知道。基本上,您要将fieldType
(const char*
}与SUPERFICIE
(long
)进行比较,并且没有隐式比较器函数来执行该转换,并且所以编译器会抛出错误。
你能做什么:
setField
和long
const char*
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;
}
进一步评论:
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
一起使用的技术称为完美转发。这用于以通用方式移动语义或复制语义。您可以查看转发参考或通用参考。
有趣的是使用成员指针。指向成员的指针就像一个类成员的别名。换句话说,您可以使用别名,而不是直接使用类的成员;你可以使用指向成员的指针。
当与特定实例一起使用时,指向成员的指针就像访问成员指向的成员一样。它们与运算符.*
或运算符->*
一起使用。操作符的左侧是对象,右侧是指向成员的指针。
在我的示例中,CONTINENT
,PAYS
和其他人指向相关成员。
您可以在此处详细了解有关poiter成员的信息:Pointers_to_data_members此处:operator_member_access