我正在尝试使用模板动态设置struct中的字段。我在代码中写了两种方法。两种方法都不起作用no member named t.age.
我如何动态设置字段?任何帮助表示赞赏。
#include <iostream>
using namespace std;
struct hello {
string name;
};
struct bye {
int age;
};
template <typename T>
void printHello(string key) {
T t;
if (key == "HELLO") {
t.name = "John";
}
else {
t.age = 0;
}
}
template <typename T>
T setStruct(T t) {
if (typeid(t) == typeid(hello)) {
t.name = "John";
}
else {
t.age = 0;
}
return t;
}
int main() {
//printHello<hello>("HELLO"); // ERROR: no member named t.age
hello h;
h = setStruct(h); // ERROR: no member named t.age
return 0;
}
答案 0 :(得分:5)
printHello
无法工作,因为您希望在运行时字符串值上执行编译时分支。
setStruct
更接近可能的解决方案但是,typeid
再次返回运行时值 - 您需要编译时分支谓词才能有条件地编译.name
或.age
访问。
在C ++ 17中,您可以使用if constexpr
和std::is_same_v
轻松解决此问题:
template <typename T>
T setStruct(T t) {
if constexpr(std::is_same_v<T, hello>) {
t.name = "John";
}
else {
t.age = 0;
}
return t;
}
更多信息on "if constexpr
vs if
" here.
请注意,您可以通过提供多个重载来简单地解决您的特定示例:
hello setStruct(hello t)
{
t.name = "John";
return t;
}
bye setStruct(bye t)
{
t.age = 0;
return t;
}
答案 1 :(得分:1)
我正在尝试使用模板动态设置struct中的字段。
我认为你使用了错误的策略。您可以使用简单的重载并完全避免与函数模板相关的问题。
hello setStruct(hello h)
{
h.name = "John";
return h;
}
bye setStruct(bye b)
{
b.age = 0;
return b;
}
只有当大多数代码与类型无关时,才能使用函数模板。
答案 2 :(得分:1)
您可以在 C ++ 11 中使用type_traits
和SFINAE。
下面是一个如何处理问题的示例:
#include <string>
#include <type_traits>
struct A {
std::string name;
};
struct B {
int age;
};
template<typename T>
typename std::enable_if<std::is_same<T, A>::value>::type
setStruct(T* t) {
t->name = "This is a string";
}
template<typename T>
typename std::enable_if<std::is_same<T, B>::value>::type
setStruct(T* t) {
t->age = 47;
}
int main(int argc, char *argv[]) {
A a;
B b;
setStruct(&a);
setStruct(&b);
return 0;
}
恕我直言,这个设计是一个糟糕的选择。它使代码不可读
可以使用其他模式轻松避免:例如多态类,重载,或重构您的数据结构。