У меня есть класс, который представляет значение и может принимать либо значение из одного числа, одной строки, массива значений или карту пар ключей-значений.
Вот текущее определение:
class Foo {
public:
typedef enum { STRING, NUMBER, ARRAY, MAP } data_type;
struct str_less {
bool operator()(const char *a, const char *b) const {
return strcmp(a,b)<0;
}
};
inline Foo(int n):type(NUMBER),number_value(n) { }
inline Foo(double n):type(NUMBER),number_value(n) { }
inline Foo(const char *s):type(STRING),string_value(s) { }
inline Foo(const std::initializer_list<std::pair<const char *const,Foo>> &arg):type(MAP),map_value(arg) { }
template<size_t N> inline Foo(const Foo (&arg)[N]):type(ARRAY) { std::copy(&arg[0], &arg[N], std::back_inserter(arg)); }
inline Foo(const std::vector<Foo> &arg):type(ARRAY),array_value(arg) { }
private:
data_type type;
double number_value = 0;
const char *string_value = "";
std::vector<Foo> array_value;
std::map<const char *,Foo, str_less> map_value;
};
Меня интересует только создание экземпляра этого класса из значений, данных во время компиляции … для моих целей он никогда не будет вызываться во время выполнения с переменными в качестве аргументов.
Из-за конструкторов в Foo
любые литеральные значения, указанные во время компиляции, будут автоматически преобразованы в тип Foo
и тогда я мог бы указать литералы почти в json-подобном виде, например:
Foo({
{"number_key", 100},
{"array_key", std::vector<Foo>
{1, 3, 4,
{
{"inner_key", "value"},
{"second_key", 500}}, "abc"}}});
Однако, как вы можете видеть, предостережение состоит в том, что мне требуется явное приведение к std :: vector для поддержки типов массивов. Есть ли способ в C ++ 11 передать литеральный массив некоторого типа в функцию, чтобы я мог вызвать template<size_t N> Foo::Foo(const Foo (&arg)[N])
надлежащим образом? Я бы очень предпочел это, потому что требование явного векторного приведения выглядит неловко и, безусловно, не однородно с остальными конструкторами, которые автоматически конвертируют свои типы. Мне интересно, есть ли другой способ, который может использовать интеллектуальное автоматическое преобразование типов, чтобы сделать это более единообразным и кратким способом?
Я видел такой код раньше:
template<std::size_t N> void do_stuff(const char (&str)[N]) ...
Который может быть вызван строковыми литералами, поэтому концептуально механизм существует для понимания литеральных массивов времени компиляции, но есть ли способ указать постоянный массив типов Другой чем char
?
Примерно так должно работать:
template <typename... Args>
Foo(Args&&... args) :
array_value{Foo(std::forward<Args>(args))...}
{}
Foo foo(4.2, "hello");
Других решений пока нет …