lundi 26 juin 2017

passing a constant literal array into a function without declaring it as a variable

I have a class that represents a value, and can assume either the value of a single number, single string, an array of values, or a map of key value pairs.

The class data content looks something like this:

class Foo {
  ...
  data_type content;
  double number_value = 0;
  const char *string_value = "";
  std::vector<Foo> array_value;
  std::map<const char *,Foo, str_less> map_value
};

(str_less is a std::less-like functor that compares two string values).

And I was originally wanting to create the appropriate constructors as follows:

Foo::Foo(double n):type(NUMBER),number_value(n) { }
Foo::Foo(const char *s):type(STRING),string_value(s) { }
template<std::size_t> Foo::Foo(const Foo (&arr)[N]):type(ARRAY) { std::copy(&arr[0],&arr[N],std::back_inserter(array_value); }
Foo::Foo(const std::initializer_list<std::pair<const char*const,int>> &arg):type(MAP),map_value(arg) { }

I am only ever interested in instantiating this class from values given at compile time... for my purposes, it would never be called at run-time with variables as arguments.

Because of the constructors in Foo, any literal values specified at compile time would get automatically type-converted into a Foo, and I could then specify literals in an almost json-like manner such as:

Foo({ "string_value", "first_key" },
    { "number_value", 1024 },
    { "nested_map", { { "nested_empty_object", { } } })

The caveat, however, is that I do not seem to have any way to specify an array, while retaining the conciseness of this initialization style.

There does not appear to be any way in C++11 to pass a literal array of some type to a function, so the templated method can never be called.

If I change the templated method to use an initializer_list of Foo, then specifications become ambiguous... is what looks like an initializer list of pairs really supposed to be calling the map oriented constructor, or is it actually an array of arrays?

The only way I've found to make this work is if I change the array constructor above to instead take a std::vector of Foo, and then explicitly specify std::vector({....}) with an intializer_list, whenever I want an array, but this feels awkward, and most definitely not homogeneous with the rest of the constructors that automatically convert their types. I am wondering if there is any other way that can utilize smart automatic type conversion to do it in a more uniform but more concise way?

Aucun commentaire:

Enregistrer un commentaire