我有以下课程:
template <typename T>
T get_value(std::string name, T defaultValue)
{
// read values from config file and assign to var; if not found use defaultValue
return defaultValue;
}
class A {
public:
A()
: myvar1_(get_value("myvar1", 0))
, myvar2_(get_value("myvar2", 1.5))
{
}
int myvar1_;
double myvar2_;
std::string asString() const {
std::stringstream str;
str << "myvar1 = " << myvar1_
<< ", myvar2 = " << myvar2_;
return str.str();
}
private:
// other things exist here, unrelated to myvar1/2
};
其中get_value
是一个从某个配置文件中读取变量值的函数,如果未找到则使用默认值。我还有myvar1_
和myvar2_
作为公共成员变量,因为它们可以直接访问,我想保留该功能,并且不想添加潜在的函数跃点。
现在,您可以看到我在很多不同的地方输入了myvar1
或myvar1_
,我想让它更加强大,以便我可以在某处以某种方式键入myvar1_, "myvar1", 0
一次(而不是键入myvar1_
3次,"myvar1"
两次),并自动获取上述函数和填充值。我有很多变量并且它们经常被添加或删除,有时我忘记初始化它们,或者错误地输入set_value
中的字符串名称,或者忘记向asString
添加新变量。 / p>
这可能吗?我很感激任何提示。
答案 0 :(得分:3)
选项1:从定义生成代码的DSL。
选项2:在配置查找中使用类外观,可能通过访问您的配置类来支持,并与C ++ 11的成员初始化相结合。这将减少你必须重复一个变量的次数,如果你想要这个变量,那么可以用一点宏来隐藏它。
#include <iostream>
template<typename T>
class DV {
T value_;
public:
DV(const char* name, const T& defaultValue)
{
// read values from config file and assign to var; if not found use defaultValue
value_ = defaultValue;
}
operator const T& () const { return value_; }
};
using DVInt = DV<int>;
using DVStr = DV<const char*>;
struct A {
int i_ = DVInt("i", 42);
const char* str_ = DVStr("str", "hello");
A() = default;
};
int main() {
A a;
std::cout << a.i_ << ", " << a.str_ << "\n";
}
- 编辑 -
使用宏减少一个实例。
而不是using
语句:
#include <iostream>
template<typename T>
class DV {
T value_;
public:
DV(const char* name, const T& defaultValue)
{
// read values from config file and assign to var; if not found use defaultValue
value_ = defaultValue;
}
operator const T& () const { return value_; }
};
#define CONCAT(x, y) x ## y
#define DVDecl(T, name, def) T CONCAT(name, _) = DV<T>(#name, def)
#define DVInt(name, def) DVDecl(int, name, def)
#define DVCStr(name, def) DVDecl(const char*, name, def)
struct A {
DVInt(myvar1, 42);
DVCStr(myvar2, "hello");
A() = default;
};
int main() {
A a;
std::cout << a.myvar1_ << ", " << a.myvar2_ << "\n";
}
但这并不能消除您手动将它们添加到asString
的需要。
答案 1 :(得分:0)
我最终得到了一个宏观解决方案,大量借用了不同的SO答案:
#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
#define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
#define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
#define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
#define EVAL(...) EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))
#define MAP_END(...)
#define MAP_OUT
#define MAP_GET_END0() 0, MAP_END
#define MAP_GET_END1(...) 0
#define GET_MACRO(_0, _1, _2, _3, _4, NAME, ...) NAME
#define MAP_GET_END(...) GET_MACRO(_0, ##__VA_ARGS__, MAP_GET_END1, MAP_GET_END1, MAP_GET_END1, MAP_GET_END1, MAP_GET_END0)(__VA_ARGS__)
#define MAP_NEXT0(item, next, ...) next MAP_OUT
#define MAP_NEXT1(item, next) MAP_NEXT0 (item, next, 0)
#define MAP_NEXT(item, next) MAP_NEXT1 (MAP_GET_END item, next)
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
#define DEFINE_VARS_T(TYPE, NAME, DEFAULT_VALUE) \
TYPE NAME##_;
#define DEFINE_VARS(TUPLE) DEFINE_VARS_T TUPLE
#define CONSTRUCT_VARS_T(TYPE, NAME, DEFAULT_VALUE) \
NAME##_ = get_value(#NAME, DEFAULT_VALUE);
#define CONSTRUCT_VARS(TUPLE) CONSTRUCT_VARS_T TUPLE
#define PRINT_VARS_T(TYPE, NAME, DEFAULT_VALUE) \
<< #NAME << " = " << NAME##_ << ", "
#define PRINT_VARS(TUPLE) PRINT_VARS_T TUPLE
#define CONFIG_VARS(...) \
MAP(DEFINE_VARS, __VA_ARGS__) \
A() { \
MAP(CONSTRUCT_VARS, __VA_ARGS__) \
} \
std::string asString() const { \
std::stringstream str; \
str MAP(PRINT_VARS, __VA_ARGS__); \
return str.str(); \
}
template <typename T>
T get_value(std::string name, T defaultValue)
{
// read values from config file and assign to var
return defaultValue;
}
class A {
public:
CONFIG_VARS
(
(int, myvar1, 0),
(double, myvar2, 1.5),
(std::string, myvar3, "what")
)
private:
// other things exist here, unrelated to myvar1/2
};